wayneeseguin-dynamic_reports 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -1,7 +1,7 @@
1
1
  = Dynamic Reports
2
2
 
3
3
  A dynamic reporting engine for Ruby / Rails
4
-
4
+
5
5
  == Reports
6
6
 
7
7
  The dynamic reports gem was created to fill a HUGE hole that we felt existed in the
@@ -114,32 +114,90 @@
114
114
  label_column "created_at"
115
115
  end
116
116
 
117
- == Stylizing
118
-
119
- The reports are, by default, stylized with an inline style sheet. The styles produce a nicely formatted grid with
120
- a white on black header row and black on white columns with a gray border througout.
117
+ == External Links
121
118
 
122
- You can create your own styles by simply adding a class_name object to the report definition as such:
123
-
124
- class OrdersReport < DynamicReports::Report
125
- title "Orders Report"
126
- subtitle "All orders recorded in database"
127
- columns :total, :created_at
119
+ Dynamic Reports supports linking from any column within your table. To add a link to a column, add the following
120
+ to a report definition:
121
+
122
+ link :column, url
123
+
124
+ For example:
125
+
126
+ class OrdersReport < DynamicReports::Report
127
+ title "Orders Report"
128
+ subtitle "All orders recorded in database"
129
+ columns :total, :created_at
130
+
131
+ link :total, '/report/daily_sales'
132
+ end
133
+
134
+ You can also pass parameters to the URL based on values from the underlying model. To pass a parameter, surround the
135
+ field name with {}. The parameter does NOT need to be a displayed, column. For example, you might want to pass
136
+ an external link an ID column but not display this column on the table.
137
+
138
+ For example:
139
+
140
+ class OrdersReport < DynamicReports::Report
141
+ title "Orders Report"
142
+ subtitle "All orders recorded in database"
143
+ columns :total, :created_at
144
+
145
+ link :total, '/report/item_sales?id={id}' # => Will substitute ID for the value of ID associated with that record
146
+ end
147
+
148
+
149
+ == Subreports
128
150
 
129
- class_name "my_class_name"
130
- end
151
+ Dynamic Reports supports the display of a sub-report within any report. This is accomplished using the jQuery library
152
+ available at http://www.jquery.com.
153
+
154
+ Sub-reports are created using the same definition format that you would use to create a standard report. The only
155
+ difference is that it is displayed INLINE when an associated link is clicked.
156
+
157
+ A sub-report is defined using the same format as a LINK above, but is labeled as:
158
+
159
+ subreport :column, url
160
+
161
+ For example, if you wanted to show all sales and allow a user to click on a specific item to see all historic sales
162
+ inline for just that item, you would do the following:
163
+
164
+ IN CONTROLLER:
165
+
166
+ def orders
167
+ @orders = Order.find(:all, :limit => 25)
168
+ render :text => OrdersReport.on(@orders).to_html, :layout => "application"
169
+ end
170
+
171
+ def item_sales
172
+ @item_orders = Order.find_by_id(params[:id])
173
+ render :text => ItemSales.on(@orders).to_html, :layout => "application"
174
+ end
175
+
176
+ REPORT DEFINITIONS
177
+
178
+ class OrdersReport < DynamicReports::Report
179
+ title "Orders Report"
180
+ subtitle "All orders recorded in database"
181
+ columns :total, :created_at
182
+
183
+ subreport :total, '/report/item_sales?id={id}' # => Will substitute ID for the value of ID associated with that record
184
+ end
185
+
186
+ class ItemSales < DynamicReports::Report
187
+ columns :item, :price, :created_at
188
+ end
189
+
190
+ Subreports can also be nested.
191
+
192
+ == Rails Usage
131
193
 
132
- This will cause DR to simply not include the inline style. From there you can customer the styles using the
133
- following sub-classes for your class name, for example:
194
+ The gem includes a stylesheet and javascript based on jQuery. To add both to your Rails project,
195
+ simply type "drsetup" from the project root. This will add:
134
196
 
135
- .my_class_name .report_title {}
136
- .my_class_name .report_subtitle {}
137
- .my_class_name table tr th {}
138
- .my_class_name table tr td {}
139
- .my_class_name .report_charts {} // all charts are displayed within this div
140
- .my_class_name .report_chart {} // represents an individual chart
197
+ public/stylesheets/dynamic_reports.css (controls style of dynamic reports)
198
+ public/javascripts/dynamic_reports.js (controls display of subreports)
141
199
 
142
- == Rails Usage
200
+ You can then modify these files as you see fit.
143
201
 
144
202
  Inside the initializer block in config/environment.rb
145
203
 
@@ -179,7 +237,7 @@
179
237
  == Thanks To
180
238
 
181
239
  * Daniel Neighman
182
- * Kenneth Kalmer (And his friend :))
240
+ * Kenneth Kalmer & Nic Young
183
241
  * Yehuda Katz
184
242
 
185
243
  For their encouragement, feedback and advise.
data/README.rdoc CHANGED
@@ -1,7 +1,7 @@
1
1
  = Dynamic Reports
2
2
 
3
3
  A dynamic reporting engine for Ruby / Rails
4
-
4
+
5
5
  == Reports
6
6
 
7
7
  The dynamic reports gem was created to fill a HUGE hole that we felt existed in the
@@ -114,32 +114,90 @@
114
114
  label_column "created_at"
115
115
  end
116
116
 
117
- == Stylizing
118
-
119
- The reports are, by default, stylized with an inline style sheet. The styles produce a nicely formatted grid with
120
- a white on black header row and black on white columns with a gray border througout.
117
+ == External Links
121
118
 
122
- You can create your own styles by simply adding a class_name object to the report definition as such:
123
-
124
- class OrdersReport < DynamicReports::Report
125
- title "Orders Report"
126
- subtitle "All orders recorded in database"
127
- columns :total, :created_at
119
+ Dynamic Reports supports linking from any column within your table. To add a link to a column, add the following
120
+ to a report definition:
121
+
122
+ link :column, url
123
+
124
+ For example:
125
+
126
+ class OrdersReport < DynamicReports::Report
127
+ title "Orders Report"
128
+ subtitle "All orders recorded in database"
129
+ columns :total, :created_at
130
+
131
+ link :total, '/report/daily_sales'
132
+ end
133
+
134
+ You can also pass parameters to the URL based on values from the underlying model. To pass a parameter, surround the
135
+ field name with {}. The parameter does NOT need to be a displayed, column. For example, you might want to pass
136
+ an external link an ID column but not display this column on the table.
137
+
138
+ For example:
139
+
140
+ class OrdersReport < DynamicReports::Report
141
+ title "Orders Report"
142
+ subtitle "All orders recorded in database"
143
+ columns :total, :created_at
144
+
145
+ link :total, '/report/item_sales?id={id}' # => Will substitute ID for the value of ID associated with that record
146
+ end
147
+
148
+
149
+ == Subreports
128
150
 
129
- class_name "my_class_name"
130
- end
151
+ Dynamic Reports supports the display of a sub-report within any report. This is accomplished using the jQuery library
152
+ available at http://www.jquery.com.
153
+
154
+ Sub-reports are created using the same definition format that you would use to create a standard report. The only
155
+ difference is that it is displayed INLINE when an associated link is clicked.
156
+
157
+ A sub-report is defined using the same format as a LINK above, but is labeled as:
158
+
159
+ subreport :column, url
160
+
161
+ For example, if you wanted to show all sales and allow a user to click on a specific item to see all historic sales
162
+ inline for just that item, you would do the following:
163
+
164
+ IN CONTROLLER:
165
+
166
+ def orders
167
+ @orders = Order.find(:all, :limit => 25)
168
+ render :text => OrdersReport.on(@orders).to_html, :layout => "application"
169
+ end
170
+
171
+ def item_sales
172
+ @item_orders = Order.find_by_id(params[:id])
173
+ render :text => ItemSales.on(@orders).to_html, :layout => "application"
174
+ end
175
+
176
+ REPORT DEFINITIONS
177
+
178
+ class OrdersReport < DynamicReports::Report
179
+ title "Orders Report"
180
+ subtitle "All orders recorded in database"
181
+ columns :total, :created_at
182
+
183
+ subreport :total, '/report/item_sales?id={id}' # => Will substitute ID for the value of ID associated with that record
184
+ end
185
+
186
+ class ItemSales < DynamicReports::Report
187
+ columns :item, :price, :created_at
188
+ end
189
+
190
+ Subreports can also be nested.
191
+
192
+ == Rails Usage
131
193
 
132
- This will cause DR to simply not include the inline style. From there you can customer the styles using the
133
- following sub-classes for your class name, for example:
194
+ The gem includes a stylesheet and javascript based on jQuery. To add both to your Rails project,
195
+ simply type "drsetup" from the project root. This will add:
134
196
 
135
- .my_class_name .report_title {}
136
- .my_class_name .report_subtitle {}
137
- .my_class_name table tr th {}
138
- .my_class_name table tr td {}
139
- .my_class_name .report_charts {} // all charts are displayed within this div
140
- .my_class_name .report_chart {} // represents an individual chart
197
+ public/stylesheets/dynamic_reports.css (controls style of dynamic reports)
198
+ public/javascripts/dynamic_reports.js (controls display of subreports)
141
199
 
142
- == Rails Usage
200
+ You can then modify these files as you see fit.
143
201
 
144
202
  Inside the initializer block in config/environment.rb
145
203
 
@@ -179,7 +237,7 @@
179
237
  == Thanks To
180
238
 
181
239
  * Daniel Neighman
182
- * Kenneth Kalmer (And his friend :))
240
+ * Kenneth Kalmer & Nic Young
183
241
  * Yehuda Katz
184
242
 
185
243
  For their encouragement, feedback and advise.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{dynamic_reports}
5
- s.version = "0.0.3"
5
+ s.version = "0.0.4"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Wayne E. Seguin", "Joshua Lippiner"]
@@ -22,7 +22,14 @@ require "dynamic_reports/vendor/google_chart"
22
22
  # require "dynamic_reports/rails"
23
23
  # For now placing the code right here:
24
24
  if defined?(Rails)
25
- # Load all defined reports.
25
+ # ath_to_lib = File.join(Rails.root, "app") #adjust if necessary
26
+ # path_to_tree = "#{path_to_lib}/reports"
27
+ # Dir["#{path_to_tree}/**/*.rb"].each { |fn|
28
+ # fn =~ /^#{Regexp.escape(path_to_lib)}\/(.*)\.rb$/
29
+ # require $1
30
+ # }
31
+
32
+ # Load all defined reports.
26
33
  # Question: How to get Rails to reload files other than ones matching the requested constant...
27
34
  #Dir.glob("#{File.join(Rails.root, "app", "reports")}/*.rb").each { |file| require file }
28
35
  ActiveSupport::Dependencies.load_paths << File.join(Rails.root, "app", "reports")
@@ -44,4 +51,3 @@ if defined?(Rails)
44
51
 
45
52
  # TODO: Generator
46
53
  end
47
-
@@ -8,7 +8,7 @@ module DynamicReports
8
8
  class Report
9
9
  @@default_engine = "erb"
10
10
 
11
- attr_accessor :name, :title, :sub_title, :columns, :charts, :records, :template, :class_name, :styles
11
+ attr_accessor :name, :title, :sub_title, :columns, :charts, :records, :template, :class_name, :styles, :links
12
12
 
13
13
  # views accessor, array of view paths.
14
14
  def views
@@ -170,6 +170,50 @@ module DynamicReports
170
170
  chart_options = chart_options.shift || {}
171
171
  charts(Chart.configure(name, chart_options, &block))
172
172
  end
173
+
174
+ # Return an array of links defined for the report.
175
+ def links(object=nil)
176
+ options[:links] ||= []
177
+ options[:links] << object if object
178
+ options[:links]
179
+ end
180
+
181
+ # Define a link for the report
182
+ #
183
+ # Pass parameters within {}. Parameters are replaced with the row values
184
+ # from passed records. You do NOT need to include a parameter value as a
185
+ # report column for it to be used in a link. For example, you might
186
+ # want to generate a link with an ID field in it but not display that id
187
+ # in the actual report. Just include {id} to do this.
188
+ #
189
+ # Example:
190
+ #
191
+ # link :visits, '/reports/{visit}/details?date={recorded_at}'
192
+ #
193
+ def link(column, url, link_options=nil)
194
+ links({:column => column, :url => url, :link_options => link_options})
195
+ end
196
+
197
+ # Define an inline subreport for the report
198
+ #
199
+ # Pass parameters within {}. Parameters are replaced with the row values
200
+ # from passed records. You do NOT need to include a parameter value as a
201
+ # report column for it to be used in a link. For example, you might
202
+ # want to generate a subreport with an ID field in it but not display that id
203
+ # in the actual report. Just include {id} to do this.
204
+ #
205
+ # Example:
206
+ #
207
+ # subreport :visits, '/reports/{visit}/details?date={recorded_at}'
208
+ #
209
+ # The subreport should be created using the same report definition style
210
+ # that you use for any other report.
211
+ #
212
+ def subreport(column, url, link_options=nil)
213
+ link_options ||= {}
214
+ link_options.merge!({:class => 'sub_report_link'})
215
+ links({:column => column, :url => url, :link_options => link_options})
216
+ end
173
217
 
174
218
  # Method for instanciating a report instance on a set of given records.
175
219
  #
@@ -187,14 +231,6 @@ module DynamicReports
187
231
  def on(records)
188
232
  new(records, @options)
189
233
  end
190
-
191
- #--
192
- # Methods for definining a sub report
193
- #def link_column
194
- #end
195
- #def link_rows
196
- #end
197
-
198
234
  end
199
235
 
200
236
  # Instantiate the report on a set of records.
@@ -32,7 +32,7 @@ module DynamicReports
32
32
 
33
33
  # TODO: Add Report Helpers for injection
34
34
  def titleize(object)
35
- object.to_s.split('_').each{ |word| word.capitalize! }.join(' ')
35
+ object.to_s.split('_').each{ |word| word.capitalize! }.join(' ')
36
36
  end
37
37
 
38
38
  def commify(object)
@@ -43,9 +43,44 @@ module DynamicReports
43
43
  end
44
44
  end
45
45
 
46
+ def linkcheck(record, column_object)
47
+ val = ''
48
+
49
+ if column_object.is_a?(Hash)
50
+ if column_object.keys.include?(:column)
51
+ column = column_object[:column]
52
+ else
53
+ column = column_object.keys.first # => Josh shortcut :)
54
+ end
55
+ else
56
+ column = column_object
57
+ end
58
+
59
+ report.links.each do |link|
60
+ if link[:column] == column
61
+ url = link[:url]
62
+ url.scan(/\{(\w+)\}/).each do |parameter|
63
+ parameter = parameter.to_s
64
+ url = url.gsub("{#{parameter}}", CGI::escape(get_record_value(record, parameter.to_sym).to_s))
65
+ end
66
+
67
+ url_attribute_str = []
68
+ link[:link_options].keys.each do |key|
69
+ url_attribute_str << "#{key}='#{link[:link_options][key]}'"
70
+ end if link[:link_options]
71
+
72
+ val = "<a href='#{url}' #{url_attribute_str.join(' ')}>#{get_record_value(record,column)}</a>"
73
+ break
74
+ end if link[:column]
75
+ end if report.links
76
+
77
+ val.blank? ? get_record_value(record,column) : val
78
+ end
79
+
80
+
46
81
  def chart_url(chart,report)
47
82
  columns = chart.columns ? chart.columns : report.columns
48
- chart_type = chart.type.nil? ? :line : chart.type.to_sym
83
+ chart_type = chart.type.nil? ? :line : chart.type.to_sym
49
84
  case chart_type
50
85
  when :line
51
86
  Charts.line_chart(chart,columns,report)
@@ -62,7 +97,7 @@ module DynamicReports
62
97
  end
63
98
 
64
99
  private
65
-
100
+
66
101
  def render(engine, template, options={}, locals={})
67
102
  # merge app-level options
68
103
  options = self.class.send(engine).merge(options) if self.class.respond_to?(engine)
@@ -74,7 +109,7 @@ module DynamicReports
74
109
  content_type = options.delete(:content_type)
75
110
  locals = options.delete(:locals) || locals || {}
76
111
  locals.merge!(:report => @report, :options => options || {})
77
-
112
+
78
113
  # render template
79
114
  data, options[:filename], options[:line] = lookup_template(engine, template, views, content_type)
80
115
  output = __send__("render_#{engine}", template, data, options, locals)
@@ -101,7 +136,7 @@ module DynamicReports
101
136
  lookup_template(engine, cached[:template], views, content_type, cached[:filename], cached[:line])
102
137
  else
103
138
  filename = "#{template}.#{content_type}.#{engine}"
104
- dir = views.to_a.detect do |view|
139
+ dir = views.to_a.detect do |view|
105
140
  ::File.exists?(::File.join(view, filename))
106
141
  end
107
142
  if dir
@@ -172,7 +207,15 @@ module DynamicReports
172
207
  require engine.downcase
173
208
  end
174
209
 
175
-
176
-
210
+ def get_record_value(record, column)
211
+ if record.is_a?(Hash)
212
+ record[column]
213
+ elsif record.respond_to?(column.to_sym)
214
+ record.send(column.to_sym)
215
+ else
216
+ column
217
+ end
218
+ end
219
+
177
220
  end
178
221
  end
@@ -1,73 +1,42 @@
1
- <% if report.class_name.nil? %>
2
- <style type="text/css">
3
- .dynamic_report .report_title {
4
- font-size:16pt;
5
- font-weight:bold;
6
- margin:10px 0px;
7
- }
8
- .dynamic_report .report_sub_title {
9
- font-size:14pt;
10
- color:black;
11
- margin:10px 0px;
12
- }
13
- .dynamic_report table tr th {
14
- color: white;
15
- background: gray;
16
- padding:5px;
17
- }
18
- .dynamic_report table tr td {
19
- border: 1px solid black;
20
- padding:3px 15px;
21
- }
22
- .dynamic_report .report_charts {
23
- width:100%;
24
- }
25
-
26
- .dynamic_report .report_chart {
27
- margin:15px;
28
- }
29
- </style>
30
- <% end %>
31
-
32
1
  <div id="<%= report.class_name %>" class="dynamic_report">
33
2
  <%= "<div class='report_title'>#{report.title}</div>" if report.title %>
34
- <%= "<div class='report_sub_title'>#{report.sub_title}</div>" if report.sub_title %>
3
+ <%= "<div class='report_subtitle'>#{report.sub_title}</div>" if report.sub_title %>
35
4
  <table class="report" border="0" cellpadding="0" cellspacing="0">
36
5
  <thead class="report_header">
37
6
  <tr class="report_header_row">
38
7
  <% report.columns.each do |column| %>
39
- <th>
40
- <%= options[:titleize] ? titleize(column) : column %>
41
- </th>
8
+ <th>
9
+ <% if column.is_a?(Hash) %>
10
+ <% if column.keys.include?(:heading) %>
11
+ <%= options[:titleize] ? titleize(column[:heading]) : column[:heading] %>
12
+ <% else %>
13
+ <%= options[:titleize] ? titleize(column.values.first) : column.values.first %>
14
+ <% end %>
15
+ <% else %>
16
+ <%= options[:titleize] ? titleize(column) : column %>
17
+ <% end %>
18
+ </th>
42
19
  <% end %>
43
20
  </tr>
44
21
  </thead>
45
22
  <tbody class="report_body">
46
23
  <% report.records.each do |record| %>
47
- <tr class="report_row">
48
- <% report.columns.each do |column| %>
49
- <td>
50
- <% if record.is_a?(Hash) %>
51
- <%= (options[:commas] == true) ? commify(record[column]) : record[column] %>
52
- <% elsif record.respond_to?(column.to_sym) %>
53
- <%= (options[:commas] == true) ? commify(record.send(column.to_sym)) : record.send(column.to_sym) %>
54
- <% else %>
55
- <%= column %>
56
- <% end %>
57
- </td>
58
- <% end %>
59
- </tr>
24
+ <tr class="report_row">
25
+ <% report.columns.each do |column| %>
26
+ <td>
27
+ <%= (options[:commas] == true) ? commify(linkcheck(record,column)) : linkcheck(record,column) %>
28
+ </td>
29
+ <% end %>
30
+ </tr>
60
31
  <% end %>
61
32
  </tbody>
62
33
  </table>
63
-
34
+
64
35
  <div class="report_charts">
65
36
  <% report.charts.to_a.each do |chart| %>
66
- <span class="report_chart">
67
- <%= "<img src='#{chart_url(chart,report)}' alt='#{chart.name}'>" %>
68
- </span>
37
+ <span class="report_chart">
38
+ <%= "<img src='#{chart_url(chart,report)}' alt='#{chart.name}'>" %>
39
+ </span>
69
40
  <% end %>
70
41
  </div>
71
-
72
42
  </div>
73
-
@@ -1,31 +1,3 @@
1
- - if report.class_name.nil?
2
- %style{type => "text/css"}
3
- \.dynamic_report .report_title {
4
- font-size:16pt;
5
- font-weight:bold;
6
- margin:10px 0px;
7
- }
8
- \.dynamic_report .report_sub_title {
9
- font-size:14pt;
10
- color:black;
11
- margin:10px 0px;
12
- }
13
- \.dynamic_report table tr th {
14
- color: white;
15
- background: gray;
16
- padding:5px;
17
- }
18
- \.dynamic_report table tr td {
19
- border: 1px solid black;
20
- padding:3px 15px;
21
- }
22
- \.dynamic_report .report_charts {
23
- width:100%;
24
- }
25
- \.dynamic_report .report_chart {
26
- margin:15px;
27
- }
28
-
29
1
  .dynamic_report{ :id => report.class_name }
30
2
  - if report.title
31
3
  %h2.report_title
@@ -40,18 +12,19 @@
40
12
  %tr.report_header_row
41
13
  - report.columns.each do |column|
42
14
  %th
43
- = options[:titleize] ? titleize(column) : column
15
+ - if column.is_a?(Hash)
16
+ - if column.keys.include?(:heading)
17
+ = options[:titleize] ? titleize(column[:heading]) : column[:heading]
18
+ -else
19
+ = options[:titleize] ? titleize(column.values.first) : column.values.first
20
+ -else
21
+ = options[:titleize] ? titleize(column) : column
44
22
  %tbody.report_body
45
23
  - report.records.each do |record|
46
24
  %tr.report_row
47
25
  - report.columns.each do |column|
48
26
  %td
49
- - if record.is_a?(Hash)
50
- = (options[:commas] == true) ? commify(record[column]) : record[column]
51
- - elsif record.respond_to?(column.to_sym)
52
- = (options[:commas] == true) ? commify(record.send(column.to_sym)) : record.send(column.to_sym)
53
- - else
54
- = column
27
+ = (options[:commas] == true) ? commify(linkcheck(record,column)) : linkcheck(record,column)
55
28
 
56
29
  - if report.charts && report.charts.class === Hash
57
30
  - report.charts.each_pair do |name, chart|
@@ -59,4 +32,3 @@
59
32
  %h2
60
33
  = name
61
34
  %img{:src => chart_url(chart), :alt => name}
62
-
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wayneeseguin-dynamic_reports
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wayne E. Seguin
@@ -46,6 +46,7 @@ files:
46
46
  - README.rdoc
47
47
  has_rdoc: false
48
48
  homepage: http://dynamicreports.rubyforge.org/
49
+ licenses:
49
50
  post_install_message:
50
51
  rdoc_options:
51
52
  - --inline-source
@@ -67,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
68
  requirements: []
68
69
 
69
70
  rubyforge_project: dynamicreports
70
- rubygems_version: 1.2.0
71
+ rubygems_version: 1.3.5
71
72
  signing_key:
72
73
  specification_version: 3
73
74
  summary: Dynamic Ruby Reporting Engine with support for Charts