juno-report 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +14 -0
- data/LICENSE.txt +22 -0
- data/README.md +197 -0
- data/Rakefile +1 -0
- data/juno-report.gemspec +21 -0
- data/lib/juno-report.rb +32 -0
- data/lib/juno-report/pdf.rb +234 -0
- data/lib/juno-report/pdf/behaviors.rb +18 -0
- data/lib/juno-report/report_object.rb +9 -0
- data/lib/juno-report/version.rb +3 -0
- metadata +73 -0
data/.gitignore
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
tmp
|
2
|
+
spec/reports
|
3
|
+
|
4
|
+
*.gem
|
5
|
+
InstalledFiles
|
6
|
+
*.rbc
|
7
|
+
.config
|
8
|
+
rdoc
|
9
|
+
test/version_tmp
|
10
|
+
lib/bundler/man
|
11
|
+
.bundle
|
12
|
+
pkg
|
13
|
+
coverage
|
14
|
+
.yardoc
|
15
|
+
junoreport.sublime-project
|
16
|
+
junoreport.sublime-workspace
|
17
|
+
# YARD artifacts
|
18
|
+
test/tmp
|
19
|
+
_yardoc
|
20
|
+
doc/
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Edson Júnior
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
# Juno Report
|
2
|
+
|
3
|
+
Cry with Report Generation? Nevermore!
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'juno-report'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install juno-report
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
The generating reports is based on a YAML file with all rules, with the fields and their settings, divided by sections.
|
22
|
+
|
23
|
+
### Body section
|
24
|
+
|
25
|
+
Represents the records which will be iterated to report generating
|
26
|
+
|
27
|
+
```yaml
|
28
|
+
# example.yml
|
29
|
+
body:
|
30
|
+
settings: {posY: 40, height: 25}
|
31
|
+
fields:
|
32
|
+
test_field1: [10]
|
33
|
+
test_field2: [220]
|
34
|
+
test_field3: [430, {column: "Named Test Field 3"}]
|
35
|
+
footer:
|
36
|
+
label_total: [10, {value: "Total"}]
|
37
|
+
totalizer: [220, {behavior: count}]
|
38
|
+
test_field3: [430, {behavior: sum}]
|
39
|
+
```
|
40
|
+
The [body] section ***must*** have three rules:
|
41
|
+
|
42
|
+
* `settings`: Defines some configurations for body, like their height and ypos.
|
43
|
+
* `fields`: Describes each field of record to be iterated.
|
44
|
+
* `footer`: Drawn at the end of all printed records and calculates fields according behavior parameter.
|
45
|
+
|
46
|
+
Each of these rules receives a array, where the first position is an integer representing the field horizontal position and
|
47
|
+
the second position is a hash with some configurations.
|
48
|
+
|
49
|
+
|
50
|
+
##### Settings
|
51
|
+
|
52
|
+
* `height`: Set the of each row at report [Integer].
|
53
|
+
* `posY`: Relative vertical position of last row at report [Integer].
|
54
|
+
* `groups`: Describes which groups will be printed (More bellow) [Array].
|
55
|
+
|
56
|
+
##### Fields
|
57
|
+
|
58
|
+
* `size`: Font size of the field [Integer].
|
59
|
+
* `align`: Defines the text alignment for each value [left|center|right].
|
60
|
+
* `font`: Supports all font type provided by Prawn gem (See more in http://rubydoc.info/gems/prawn/Prawn/Font/AFM).
|
61
|
+
* `style`: Stylistic variations of a font [bold|italic].
|
62
|
+
* `value`: Fixed text to be printed [string].
|
63
|
+
* `column`: The header are "humanized" automatically, but you can set other value manually [string].
|
64
|
+
|
65
|
+
##### Footer
|
66
|
+
|
67
|
+
* `behavior`: Specify a function to be performed, sending as parameter the fieldname value [string].
|
68
|
+
* `label`: Preppends a text to fieldname value specified [string].
|
69
|
+
* `value`: Fixed text to be printed (fieldname value will be ignored) [string].
|
70
|
+
|
71
|
+
With theses configurations already is possible generate a basic report, without groups feature.
|
72
|
+
For this we need call the generate method on JunoReport module:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
# test.rb
|
76
|
+
require 'juno-report'
|
77
|
+
|
78
|
+
data = [
|
79
|
+
{:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 50},
|
80
|
+
{:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 7},
|
81
|
+
{:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 10},
|
82
|
+
{:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 5},
|
83
|
+
{:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 2},
|
84
|
+
{:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 4},
|
85
|
+
{:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 24}
|
86
|
+
]
|
87
|
+
|
88
|
+
JunoReport::generate(data, :report => 'example')
|
89
|
+
```
|
90
|
+
|
91
|
+
The first parameter must be a set of hash or objects which represent the report data. And the second parameter is a hash
|
92
|
+
with the report settings, that can be:
|
93
|
+
|
94
|
+
* `report`: The source of all rules. Must be a YAML file [string].
|
95
|
+
* `type`: Specify if the report will be writed on the disc or returned to the caller such a stream [:file|:stream]
|
96
|
+
* `filename`: Defines the report name which will be writed on disc. If not specified, the default name is "report.pdf" [string].
|
97
|
+
|
98
|
+
### Page section
|
99
|
+
|
100
|
+
You may want to print a title every time that a page is created. You simply insert a [page] section.
|
101
|
+
|
102
|
+
```yaml
|
103
|
+
# example.yml
|
104
|
+
page:
|
105
|
+
fields:
|
106
|
+
title1: [260, {size: 24, align: center, value: "Test Report"}]
|
107
|
+
subtitle1: [260, {size: 20, posY: 20, align: center, value: "Generated by Juno Report"}]
|
108
|
+
body:
|
109
|
+
settings: {posY: 40, height: 25}
|
110
|
+
fields:
|
111
|
+
test_field1: [10]
|
112
|
+
test_field2: [220]
|
113
|
+
test_field3: [430, {column: "Named Test Field 3"}]
|
114
|
+
footer:
|
115
|
+
label_total: [10, {value: "Total"}]
|
116
|
+
totalizer: [220, {behavior: count}]
|
117
|
+
test_field3: [430, {behavior: sum}]
|
118
|
+
```
|
119
|
+
|
120
|
+
### Groups section
|
121
|
+
|
122
|
+
For each item in groups parameter at body section you should create a section with same name.
|
123
|
+
This section represents the header configurations to every time that the group is printed and behaves like [body] section.
|
124
|
+
|
125
|
+
```yaml
|
126
|
+
# example.yml
|
127
|
+
page:
|
128
|
+
fields:
|
129
|
+
title1: [260, {size: 24, align: center, value: "Test Report"}]
|
130
|
+
subtitle1: [260, {size: 20, posY: 20, align: center, value: "Generated by Juno Report"}]
|
131
|
+
body:
|
132
|
+
settings: {posY: 40, height: 30, groups: [group_field1, group_field2]}
|
133
|
+
fields:
|
134
|
+
test_field1: [10]
|
135
|
+
test_field2: [220]
|
136
|
+
test_field3: [420, {column: "Named Test Field 3"}]
|
137
|
+
footer:
|
138
|
+
label_total: [10, {value: "Total"}]
|
139
|
+
totalizer1: [220, {behavior: count}]
|
140
|
+
test_field3: [420, {behavior: sum}]
|
141
|
+
group_field1:
|
142
|
+
settings: {posY: 30, height: 10}
|
143
|
+
fields:
|
144
|
+
group_field1: [10, size: 25]
|
145
|
+
footer:
|
146
|
+
group_field1: [10, {label: "Total "}]
|
147
|
+
totalizer1: [220, {behavior: count}]
|
148
|
+
test_field3: [420, {behavior: sum}]
|
149
|
+
group_field2:
|
150
|
+
settings: {posY: 30, height: 25}
|
151
|
+
fields:
|
152
|
+
group_field2: [10, size: 17]
|
153
|
+
footer:
|
154
|
+
group_field2: [10, {label: "Total "}]
|
155
|
+
totalizer1: [220, {behavior: count}]
|
156
|
+
test_field3: [420, {behavior: sum}]
|
157
|
+
```
|
158
|
+
|
159
|
+
Every time that a "group field" value changes, the group will be printed.
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
# test.rb
|
163
|
+
require 'juno-report'
|
164
|
+
|
165
|
+
data = [
|
166
|
+
{:test_field1 => 'Test Value 1', :test_field2 => "Test Value 1", :test_field3 => 50, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 1'},
|
167
|
+
{:test_field1 => 'Test Value 2', :test_field2 => "Test Value 2", :test_field3 => 16, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 1'},
|
168
|
+
{:test_field1 => 'Test Value 5', :test_field2 => "Test Value 3", :test_field3 => 7, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 1'},
|
169
|
+
{:test_field1 => 'Test Value 3', :test_field2 => "Test Value 9", :test_field3 => 10, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 2'},
|
170
|
+
{:test_field1 => 'Test Value 3', :test_field2 => "Test Value 2", :test_field3 => 4, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 2'},
|
171
|
+
{:test_field1 => 'Test Value 9', :test_field2 => "Test Value 4", :test_field3 => 10, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 2'},
|
172
|
+
{:test_field1 => 'Test Value 7', :test_field2 => "Test Value 5", :test_field3 => 5, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 3'},
|
173
|
+
{:test_field1 => 'Test Value 3', :test_field2 => "Test Value 5", :test_field3 => 2, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 3'},
|
174
|
+
{:test_field1 => 'Test Value 3', :test_field2 => "Test Value 2", :test_field3 => 27, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 1'},
|
175
|
+
{:test_field1 => 'Test Value 3', :test_field2 => "Test Value 5", :test_field3 => 2, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 1'},
|
176
|
+
{:test_field1 => 'Test Value 0', :test_field2 => "Test Value 4", :test_field3 => 13, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 1'},
|
177
|
+
{:test_field1 => 'Test Value 4', :test_field2 => "Test Value 7", :test_field3 => 7, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 1'},
|
178
|
+
{:test_field1 => 'Test Value 1', :test_field2 => "Test Value 3", :test_field3 => 28, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 1'},
|
179
|
+
{:test_field1 => 'Test Value 4', :test_field2 => "Test Value 5", :test_field3 => 4, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 2'},
|
180
|
+
{:test_field1 => 'Test Value 5', :test_field2 => "Test Value 6", :test_field3 => 24, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 2'}
|
181
|
+
]
|
182
|
+
|
183
|
+
JunoReport::generate(data, :report => 'example', :filename => 'juno-report.pdf')
|
184
|
+
```
|
185
|
+
|
186
|
+
## Contributors
|
187
|
+
|
188
|
+
2. Edson Júnior (http://github.com/ebfjunior)
|
189
|
+
|
190
|
+
## Contributing
|
191
|
+
|
192
|
+
1. Fork it
|
193
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
194
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
195
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
196
|
+
5. Create new Pull Request
|
197
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/juno-report.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require 'juno-report/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "juno-report"
|
7
|
+
gem.version = JunoReport::VERSION
|
8
|
+
gem.platform = Gem::Platform::RUBY
|
9
|
+
gem.authors = ["Edson Júnior"]
|
10
|
+
gem.email = ["ejunior.batista@gmail.com"]
|
11
|
+
gem.description = "A simple, but efficient, report genarator yaml based"
|
12
|
+
gem.summary = "Juno Reports generates reports with the minimum configuration and effort"
|
13
|
+
gem.homepage = "http://github.com/ebfjunior/juno-report"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split("\n")
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "prawml"
|
21
|
+
end
|
data/lib/juno-report.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "juno-report/version"
|
2
|
+
require "juno-report/pdf"
|
3
|
+
require "juno-report/pdf/behaviors"
|
4
|
+
require "prawml"
|
5
|
+
|
6
|
+
module JunoReport
|
7
|
+
autoload :ReportObject, 'juno-report/report_object'
|
8
|
+
|
9
|
+
def self.generate(collection, options)
|
10
|
+
rules = "#{options[:report]}.yml"
|
11
|
+
|
12
|
+
defaults = {
|
13
|
+
:page_layout => :portrait
|
14
|
+
}
|
15
|
+
|
16
|
+
pdf = Prawml::PDF.new rules, defaults.merge(options)
|
17
|
+
|
18
|
+
pdf.extend JunoReport::Pdf
|
19
|
+
report = pdf.generate(collection)
|
20
|
+
|
21
|
+
options[:type] ||= :file
|
22
|
+
|
23
|
+
if options[:type].eql? :file
|
24
|
+
report.render_file (options[:filename] || "report.pdf")
|
25
|
+
elsif options[:type].eql? :stream
|
26
|
+
return report
|
27
|
+
else
|
28
|
+
raise "Type options must be :file or :stream."
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
module JunoReport
|
2
|
+
module Pdf
|
3
|
+
|
4
|
+
#Responsible for generate a report, based on rules passed as parameter in Juno::Report::generate.
|
5
|
+
#Juno Reports has support groups, just by especifying them at the rules file.
|
6
|
+
#Receives a collection as parameter, which should be a Array of records of the report.
|
7
|
+
def generate(collection)
|
8
|
+
@defaults = {
|
9
|
+
:style => :normal,
|
10
|
+
:size => 12,
|
11
|
+
:align => :left,
|
12
|
+
:format => false,
|
13
|
+
:font => 'Times-Roman',
|
14
|
+
:type => :text,
|
15
|
+
:color => '000000',
|
16
|
+
:fixed => false
|
17
|
+
}
|
18
|
+
|
19
|
+
get_sections
|
20
|
+
set_pos_y
|
21
|
+
|
22
|
+
collection = [collection] unless collection.is_a?(Array)
|
23
|
+
print_section :page unless @sections[:page].nil?
|
24
|
+
set_pos_y (@sections[:body][:settings][:posY] || 0)
|
25
|
+
@current_groups = {}
|
26
|
+
@footers = {}
|
27
|
+
|
28
|
+
unless @sections[:groups].empty?
|
29
|
+
reset_groups_values
|
30
|
+
else
|
31
|
+
draw_columns
|
32
|
+
end
|
33
|
+
|
34
|
+
initialize_footer_values
|
35
|
+
can_print_footer = false
|
36
|
+
|
37
|
+
collection.each do |record|
|
38
|
+
@record = record.is_a?(Hash) ? ReportObject.new(record) : record #Convert the hash on a Object to futurely extend a module
|
39
|
+
|
40
|
+
headers_to_print, headers_height = calculate_header
|
41
|
+
|
42
|
+
unless headers_to_print.empty?
|
43
|
+
draw_footer headers_to_print, @sections[:groups] if can_print_footer
|
44
|
+
if @posY - headers_height < 2*@sections[:body][:settings][:height]
|
45
|
+
new_page
|
46
|
+
else
|
47
|
+
headers_to_print.each { |group| print_section group, @record, true }
|
48
|
+
draw_columns
|
49
|
+
end
|
50
|
+
end
|
51
|
+
can_print_footer = true
|
52
|
+
|
53
|
+
update_footer_values
|
54
|
+
print_section :body, @record
|
55
|
+
end
|
56
|
+
|
57
|
+
draw_footer(@sections[:body][:settings][:groups].collect {|group| group.to_sym}, @sections[:groups]) if has_groups?
|
58
|
+
draw_footer [:body], @sections
|
59
|
+
|
60
|
+
@pdf
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
#Creates a new page, restarting the vertical position of the pointer.
|
66
|
+
#Print the whole header for the current groups and the columns of the report.
|
67
|
+
def new_page
|
68
|
+
@pdf.start_new_page
|
69
|
+
set_pos_y
|
70
|
+
print_section :page unless @sections[:page].nil?
|
71
|
+
set_pos_y (@sections[:body][:settings][:posY] || 0)
|
72
|
+
@current_groups.each do |field, value|
|
73
|
+
print_section field.to_sym, @record, true
|
74
|
+
end
|
75
|
+
draw_columns
|
76
|
+
end
|
77
|
+
|
78
|
+
#Generic function to print a section like :body, :page or the group sections.
|
79
|
+
def print_section(section_name, values = nil, group = false)
|
80
|
+
section = !group ? @sections[section_name] : @sections[:groups][section_name]
|
81
|
+
set_pos_y(section[:settings][:posY] || 0) unless section_name.eql?(:body) || section[:settings].nil?
|
82
|
+
new_page if @posY < 30
|
83
|
+
|
84
|
+
section[:fields].each do |field, settings|
|
85
|
+
symbolize! settings[1] unless settings[1].nil?
|
86
|
+
set_pos_y settings[1][:posY] unless settings[1].nil? || settings[1][:posY].nil?
|
87
|
+
settings = [settings[0], @posY, (@defaults.merge (settings[1] || { }))]
|
88
|
+
settings[2][:style] = settings[2][:style].to_sym
|
89
|
+
set_options settings[2]
|
90
|
+
|
91
|
+
value = settings[2][:value].nil? ? (values.respond_to?(field) ? values.send(field) : "") : settings[2][:value]
|
92
|
+
draw_text value, settings
|
93
|
+
end
|
94
|
+
set_pos_y (section[:settings][:height]) unless section[:settings].nil? || section[:settings][:height].nil?
|
95
|
+
end
|
96
|
+
|
97
|
+
#Print a horizontal line with the whole width of the page.
|
98
|
+
def draw_line(y)
|
99
|
+
width = @options[:page_layout] == :portrait ? 530 : 770
|
100
|
+
@pdf.stroke { @pdf.horizontal_line 0, width, :at => y }
|
101
|
+
end
|
102
|
+
|
103
|
+
#Update the pointer vertical position to the specified value or 'zero' if the parameter is nil.
|
104
|
+
#Obs: Prawn pointer is decrescent, in other words, the left-top corner position is (0, 750). For
|
105
|
+
#semantic purposes, we set the same corner as (0, 0).
|
106
|
+
def set_pos_y(posY = nil)
|
107
|
+
height = @options[:page_layout] == :portrait ? 750 : 520
|
108
|
+
@posY = height if @posY.nil?
|
109
|
+
@posY = posY.nil? ? height : @posY - posY
|
110
|
+
end
|
111
|
+
|
112
|
+
#Convert to symbol all hash keys, recursively.
|
113
|
+
def symbolize! hash
|
114
|
+
hash.symbolize_keys!
|
115
|
+
hash.values.select{|v| v.is_a? Hash}.each{|h| symbolize!(h)}
|
116
|
+
end
|
117
|
+
|
118
|
+
#Convert the structure of the rules to facilitate the generating proccess.
|
119
|
+
def get_sections
|
120
|
+
symbolize! @rules
|
121
|
+
raise "[body] section on YAML file is needed to generate the report." if @rules[:body].nil?
|
122
|
+
@sections = {:page => @rules[:page], :body => @rules[:body], :groups => {}}
|
123
|
+
@sections[:body][:settings][:groups].each { |group| @sections[:groups][group.to_sym] = @rules[group.to_sym] } if has_groups?
|
124
|
+
end
|
125
|
+
|
126
|
+
#@current_groups storages the value for all groups. When a value is changed, the header is printed.
|
127
|
+
#This function set nil value for every item in @current_groups if the parameter is not passed. Otherwise,
|
128
|
+
#only the forward groups will be cleaned to avoid conflict problems with others groups.
|
129
|
+
def reset_groups_values current_group = nil
|
130
|
+
groups = @sections[:body][:settings][:groups]
|
131
|
+
groups.each_with_index do |group, idx|
|
132
|
+
@current_groups[group] = nil if current_group.nil? || groups.index(current_group.to_s) <= idx
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
#Calculates the headers which must be printed before print the current record.
|
138
|
+
#The function also returns the current header height to create a new page if the
|
139
|
+
#page remaining space is smaller than (header + a record height)
|
140
|
+
def calculate_header
|
141
|
+
headers = []
|
142
|
+
height = 0
|
143
|
+
@current_groups.each do |field, value|
|
144
|
+
if @record.send(field) != value
|
145
|
+
reset_groups_values field
|
146
|
+
|
147
|
+
headers << field.to_sym
|
148
|
+
height += @sections[:groups][field.to_sym][:settings][:height] + @sections[:groups][field.to_sym][:settings][:posY]
|
149
|
+
|
150
|
+
@current_groups[field] = @record.send(field)
|
151
|
+
end
|
152
|
+
end unless @current_groups.empty?
|
153
|
+
[headers, height]
|
154
|
+
end
|
155
|
+
|
156
|
+
#Create a structure to calculate the footer values for all groups. Appends the footer body to total values too.
|
157
|
+
def initialize_footer_values
|
158
|
+
@sections[:body][:settings][:groups].each do |group|
|
159
|
+
current_footer = {}
|
160
|
+
@sections[:groups][group.to_sym][:footer].each { |field, settings| current_footer[field] = nil } unless @sections[:groups][group.to_sym][:footer].nil?
|
161
|
+
@footers[group.to_sym] = current_footer unless current_footer.empty?
|
162
|
+
end if has_groups?
|
163
|
+
raise "The report must have at least a footer on body section" if @sections[:body][:footer].nil?
|
164
|
+
current_footer = {}
|
165
|
+
@sections[:body][:footer].each { |field, settings| current_footer[field] = nil }
|
166
|
+
@footers[:body] = current_footer unless current_footer.empty?
|
167
|
+
end
|
168
|
+
|
169
|
+
#Call the function that calculates the footer values for all groups and the total body footer, with
|
170
|
+
#different source for each
|
171
|
+
def update_footer_values
|
172
|
+
@sections[:body][:settings][:groups].reverse_each do |group|
|
173
|
+
calculate_footer_values group, @sections[:groups][group.to_sym][:footer]
|
174
|
+
end if has_groups?
|
175
|
+
calculate_footer_values :body, @sections[:body][:footer]
|
176
|
+
end
|
177
|
+
|
178
|
+
#Returns the values to the group passed as parameter. If :behavior setting is used, so a
|
179
|
+
#function in [lib/pdf/behaviors.rb] calculates the value of current field, else the report
|
180
|
+
#method is called
|
181
|
+
def calculate_footer_values group, source
|
182
|
+
@footers[group.to_sym].each do |field, value|
|
183
|
+
footer_rule = source[field]
|
184
|
+
symbolize! footer_rule[1]
|
185
|
+
unless footer_rule[1][:behavior].nil?
|
186
|
+
@footers[group.to_sym][field] = JunoReport::Pdf::Behaviors.send footer_rule[1][:behavior].to_sym, value, (@record.respond_to?(field) ? @record.send(field) : nil)
|
187
|
+
else
|
188
|
+
@footers[group.to_sym][field] = footer_rule[1][:value] || (footer_rule[1][:label].to_s + @record.send(field))
|
189
|
+
end unless @footers[group.to_sym].nil? || footer_rule[1].nil?
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
#Print the footers according to the groups and source specified
|
194
|
+
def draw_footer footers_to_print, source
|
195
|
+
footers_to_print.reverse_each do |group|
|
196
|
+
draw_line(@posY + @sections[:body][:settings][:height]/2)
|
197
|
+
source[group][:footer].each do |field, settings|
|
198
|
+
settings = [settings[0], @posY, (@defaults.merge (settings[1] || { }).symbolize_keys!)]
|
199
|
+
settings[2][:style] = settings[2][:style].to_sym
|
200
|
+
set_options settings[2]
|
201
|
+
draw_text @footers[group][field], settings
|
202
|
+
end
|
203
|
+
draw_line(@posY - @sections[:body][:settings][:height]/4)
|
204
|
+
set_pos_y @sections[:body][:settings][:height]
|
205
|
+
|
206
|
+
reset_footer group
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
#Resets the footer to next groups
|
211
|
+
def reset_footer(group); @footers[group].each { |field, value| @footers[group][field] = nil }; end
|
212
|
+
|
213
|
+
#Based on the Key names of the :body section at the rules, the function draw columns with
|
214
|
+
#baselines on the top and bottom of the header.
|
215
|
+
def draw_columns
|
216
|
+
@sections[:body][:fields].each do |field, settings|
|
217
|
+
settings = [settings[0], @posY, (@defaults.merge (settings[1] || { }).symbolize_keys!)]
|
218
|
+
settings[2][:style] = settings[2][:style].to_sym
|
219
|
+
set_options settings[2]
|
220
|
+
draw_line(@posY + @sections[:body][:settings][:height]/2)
|
221
|
+
field = settings[2][:column] || field.to_s.split('_').inject('') do |str, part|
|
222
|
+
str << part.camelize << " "
|
223
|
+
end
|
224
|
+
draw_text field, settings
|
225
|
+
end
|
226
|
+
draw_line(@posY - @sections[:body][:settings][:height]/2)
|
227
|
+
set_pos_y @sections[:body][:settings][:height]
|
228
|
+
end
|
229
|
+
|
230
|
+
def has_groups?
|
231
|
+
!@sections[:body][:settings][:groups].nil?
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module JunoReport
|
2
|
+
module Pdf
|
3
|
+
module Behaviors
|
4
|
+
def self.sum old_value, new_value
|
5
|
+
value = (old_value.to_f + new_value.to_f).to_s
|
6
|
+
(/^[0-9]+(?=\.)/.match value).nil? ? value : value[/^[0-9]+(?=\.)/]
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.substract old_value, new_value
|
10
|
+
old_value.to_f - new_value.to_f
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.count old_value, new_value = nil
|
14
|
+
old_value.to_i + 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class ReportObject
|
2
|
+
def initialize(hash)
|
3
|
+
hash.each do |k,v|
|
4
|
+
self.instance_variable_set("@#{k}", v)
|
5
|
+
self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")})
|
6
|
+
self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)})
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: juno-report
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Edson Júnior
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: prawml
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: A simple, but efficient, report genarator yaml based
|
31
|
+
email:
|
32
|
+
- ejunior.batista@gmail.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- Gemfile
|
39
|
+
- Gemfile.lock
|
40
|
+
- LICENSE.txt
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- juno-report.gemspec
|
44
|
+
- lib/juno-report.rb
|
45
|
+
- lib/juno-report/pdf.rb
|
46
|
+
- lib/juno-report/pdf/behaviors.rb
|
47
|
+
- lib/juno-report/report_object.rb
|
48
|
+
- lib/juno-report/version.rb
|
49
|
+
homepage: http://github.com/ebfjunior/juno-report
|
50
|
+
licenses: []
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.8.23
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Juno Reports generates reports with the minimum configuration and effort
|
73
|
+
test_files: []
|