topherfangio-active_report 0.1.1
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.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +32 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/active_report.gemspec +63 -0
- data/generators/active_report/USAGE +16 -0
- data/generators/active_report/active_report_generator.rb +20 -0
- data/generators/active_report/templates/controller.rb +2 -0
- data/generators/active_report/templates/create.html.erb +3 -0
- data/generators/active_report/templates/model.rb +9 -0
- data/generators/active_report/templates/new.html.erb +9 -0
- data/generators/active_reports_controller/USAGE +16 -0
- data/generators/active_reports_controller/active_reports_controller_generator.rb +7 -0
- data/generators/active_reports_controller/templates/active_reports_controller.rb +51 -0
- data/lib/active_report.rb +15 -0
- data/lib/active_report/base.rb +351 -0
- data/lib/active_report/core_extention.rb +15 -0
- data/lib/active_report/errors.rb +11 -0
- data/lib/active_report/validations.rb +33 -0
- data/rails/init.rb +2 -0
- data/tasks/active_report_tasks.rake +4 -0
- data/test/active_report_test.rb +39 -0
- data/test/core_extention_test.rb +15 -0
- data/test/test_helper.rb +25 -0
- metadata +80 -0
data/.document
ADDED
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2009 Topher Fangio
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
= active_report
|
|
2
|
+
|
|
3
|
+
ActiveReport is a gem designed to assist you in creating reports. Currently is supports
|
|
4
|
+
HTML and CSV reports through an intuitive interface.
|
|
5
|
+
|
|
6
|
+
== Generators
|
|
7
|
+
|
|
8
|
+
Generators are included to create all neccessary files.
|
|
9
|
+
|
|
10
|
+
To create a new report, run the following command:
|
|
11
|
+
|
|
12
|
+
ruby script/generate active_report UserReport
|
|
13
|
+
|
|
14
|
+
You also need to generate the default ActiveReportController which your report controllers
|
|
15
|
+
will extend:
|
|
16
|
+
|
|
17
|
+
ruby script/generate active_report_controller
|
|
18
|
+
|
|
19
|
+
If this file already exists, it will ask if you wish to overwrite it.
|
|
20
|
+
|
|
21
|
+
After running the two previous commands, and starting/restarting your web server (so that
|
|
22
|
+
it rereads routes.rb), you should be able to go to http://localhost/user_reports and see
|
|
23
|
+
a basic form containing a submit button that says "Generate". Clicking this button will
|
|
24
|
+
return you to the "new" page since no data was submitted. Currently you cannot submit an
|
|
25
|
+
empty report, which turns out to be a bad thing, so this is considered a bug and will be
|
|
26
|
+
fixed in a later release.
|
|
27
|
+
|
|
28
|
+
Check out the rdoc for more information on how to use the models.
|
|
29
|
+
|
|
30
|
+
== Copyright
|
|
31
|
+
|
|
32
|
+
Copyright (c) 2009 Topher Fangio. See MIT-LICENSE for details.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require 'jeweler'
|
|
6
|
+
Jeweler::Tasks.new do |gem|
|
|
7
|
+
gem.name = "active_report"
|
|
8
|
+
gem.summary = %Q{ActiveReport enables you to easily generate reports.}
|
|
9
|
+
gem.email = "fangiotophia@gmail.com"
|
|
10
|
+
gem.homepage = "http://github.com/topherfangio/active_report"
|
|
11
|
+
gem.authors = ["Topher Fangio"]
|
|
12
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
rescue LoadError
|
|
16
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
require 'rake/testtask'
|
|
20
|
+
Rake::TestTask.new(:test) do |test|
|
|
21
|
+
test.libs << 'lib' << 'test'
|
|
22
|
+
test.pattern = 'test/**/*_test.rb'
|
|
23
|
+
test.verbose = true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
begin
|
|
27
|
+
require 'rcov/rcovtask'
|
|
28
|
+
Rcov::RcovTask.new do |test|
|
|
29
|
+
test.libs << 'test'
|
|
30
|
+
test.pattern = 'test/**/*_test.rb'
|
|
31
|
+
test.verbose = true
|
|
32
|
+
end
|
|
33
|
+
rescue LoadError
|
|
34
|
+
task :rcov do
|
|
35
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
task :default => :test
|
|
41
|
+
|
|
42
|
+
require 'rake/rdoctask'
|
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
|
44
|
+
if File.exist?('VERSION.yml')
|
|
45
|
+
config = YAML.load(File.read('VERSION.yml'))
|
|
46
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
|
47
|
+
else
|
|
48
|
+
version = ""
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
52
|
+
rdoc.title = "ActiveReport #{version}"
|
|
53
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
|
54
|
+
rdoc.rdoc_files.include('README*')
|
|
55
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
56
|
+
end
|
|
57
|
+
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.1
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{active_report}
|
|
5
|
+
s.version = "0.1.1"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Topher Fangio"]
|
|
9
|
+
s.date = %q{2009-06-18}
|
|
10
|
+
s.email = %q{fangiotophia@gmail.com}
|
|
11
|
+
s.extra_rdoc_files = [
|
|
12
|
+
"README.rdoc"
|
|
13
|
+
]
|
|
14
|
+
s.files = [
|
|
15
|
+
".document",
|
|
16
|
+
".gitignore",
|
|
17
|
+
"MIT-LICENSE",
|
|
18
|
+
"README.rdoc",
|
|
19
|
+
"Rakefile",
|
|
20
|
+
"VERSION",
|
|
21
|
+
"active_report.gemspec",
|
|
22
|
+
"generators/active_report/USAGE",
|
|
23
|
+
"generators/active_report/active_report_generator.rb",
|
|
24
|
+
"generators/active_report/templates/controller.rb",
|
|
25
|
+
"generators/active_report/templates/create.html.erb",
|
|
26
|
+
"generators/active_report/templates/model.rb",
|
|
27
|
+
"generators/active_report/templates/new.html.erb",
|
|
28
|
+
"generators/active_reports_controller/USAGE",
|
|
29
|
+
"generators/active_reports_controller/active_reports_controller_generator.rb",
|
|
30
|
+
"generators/active_reports_controller/templates/active_reports_controller.rb",
|
|
31
|
+
"lib/active_report.rb",
|
|
32
|
+
"lib/active_report/base.rb",
|
|
33
|
+
"lib/active_report/core_extention.rb",
|
|
34
|
+
"lib/active_report/errors.rb",
|
|
35
|
+
"lib/active_report/validations.rb",
|
|
36
|
+
"rails/init.rb",
|
|
37
|
+
"tasks/active_report_tasks.rake",
|
|
38
|
+
"test/active_report_test.rb",
|
|
39
|
+
"test/core_extention_test.rb",
|
|
40
|
+
"test/test_helper.rb"
|
|
41
|
+
]
|
|
42
|
+
s.has_rdoc = true
|
|
43
|
+
s.homepage = %q{http://github.com/topherfangio/active_report}
|
|
44
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
|
45
|
+
s.require_paths = ["lib"]
|
|
46
|
+
s.rubygems_version = %q{1.3.1}
|
|
47
|
+
s.summary = %q{ActiveReport enables you to easily generate reports.}
|
|
48
|
+
s.test_files = [
|
|
49
|
+
"test/test_helper.rb",
|
|
50
|
+
"test/core_extention_test.rb",
|
|
51
|
+
"test/active_report_test.rb"
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
if s.respond_to? :specification_version then
|
|
55
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
56
|
+
s.specification_version = 2
|
|
57
|
+
|
|
58
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
59
|
+
else
|
|
60
|
+
end
|
|
61
|
+
else
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Creates all of the files neccessary to generate
|
|
3
|
+
a basic report and adds the appropriate route to
|
|
4
|
+
`routes.rb`. It does not create the base class
|
|
5
|
+
for the controllers, to do so, run the
|
|
6
|
+
active_reports_controller generator.
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
`./script/generate active_report UserReport`
|
|
10
|
+
|
|
11
|
+
This will create:
|
|
12
|
+
app/controllers/user_reports_controller.rb
|
|
13
|
+
app/models/user_report.rb
|
|
14
|
+
app/view/user_reports
|
|
15
|
+
app/view/user_reports/create.html.erb
|
|
16
|
+
app/view/user_reports/new.html.erb
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class ActiveReportGenerator < Rails::Generator::NamedBase
|
|
2
|
+
attr_reader :root
|
|
3
|
+
|
|
4
|
+
def manifest
|
|
5
|
+
root = "."
|
|
6
|
+
@root = File.expand_path(File.directory?(root) ? root : File.join(Dir.pwd, root))
|
|
7
|
+
|
|
8
|
+
record do |m|
|
|
9
|
+
m.template 'controller.rb', "app/controllers/#{file_name.pluralize}_controller.rb"
|
|
10
|
+
m.template 'model.rb', "app/models/#{file_name}.rb"
|
|
11
|
+
|
|
12
|
+
m.directory "app/views/#{file_name.pluralize}"
|
|
13
|
+
m.template 'create.html.erb', "app/views/#{file_name.pluralize}/create.html.erb"
|
|
14
|
+
m.template 'new.html.erb', "app/views/#{file_name.pluralize}/new.html.erb"
|
|
15
|
+
|
|
16
|
+
m.route_resources file_name.pluralize
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Creates the file containing the base class that
|
|
3
|
+
all reports extend.
|
|
4
|
+
|
|
5
|
+
Example:
|
|
6
|
+
`./script/generate active_reports_controller`
|
|
7
|
+
|
|
8
|
+
This will create:
|
|
9
|
+
app/controllers/active_reports_controller.rb
|
|
10
|
+
|
|
11
|
+
If app/controllers/active_reports_controller.rb
|
|
12
|
+
exists, it will ask you whether or not you wish
|
|
13
|
+
to overwrite the file. Generally it is safest to
|
|
14
|
+
say no in case you have made any changes (such
|
|
15
|
+
as adding a `before_filter :require_admin` or
|
|
16
|
+
similar).
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
class ActiveReportsController < ApplicationController
|
|
2
|
+
|
|
3
|
+
def new
|
|
4
|
+
@report = eval("#{self.controller_name.singularize.camelize}.new")
|
|
5
|
+
|
|
6
|
+
respond_to do |format|
|
|
7
|
+
format.html
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def create
|
|
12
|
+
model = self.controller_name.singularize.camelize
|
|
13
|
+
|
|
14
|
+
if params.nil? or params[model.underscore].nil?
|
|
15
|
+
redirect_to :action => :new and return
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
@report = eval("#{model}.new(params[:#{model.underscore}])")
|
|
19
|
+
|
|
20
|
+
respond_to do |format|
|
|
21
|
+
if @report.generate
|
|
22
|
+
format.html
|
|
23
|
+
format.xml { render :xml => @report }
|
|
24
|
+
format.csv do
|
|
25
|
+
filename = []
|
|
26
|
+
|
|
27
|
+
filename << model.underscore
|
|
28
|
+
filename << '-'
|
|
29
|
+
filename << Time.now.strftime("%Y%m%d-%H%M%S")
|
|
30
|
+
filename << '.csv'
|
|
31
|
+
|
|
32
|
+
csv = @report.to_csv
|
|
33
|
+
|
|
34
|
+
if csv.present?
|
|
35
|
+
send_data(csv, :filename => filename.join, :type => 'text/csv', :disposition => 'attachment')
|
|
36
|
+
else
|
|
37
|
+
render :text => "This report cannot be exported to a comma separated values (CSV) list."
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
format.html { render :action => "new" }
|
|
42
|
+
format.xml { render :xml => @report.errors, :status => :unprocessable_entity }
|
|
43
|
+
format.csv { render :text => 'An error occured when processing the report.' }
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def index
|
|
49
|
+
redirect_to :action => :new
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# ActiveReport
|
|
2
|
+
require 'active_report/core_extention'
|
|
3
|
+
|
|
4
|
+
require 'active_report/errors'
|
|
5
|
+
require 'active_report/validations'
|
|
6
|
+
|
|
7
|
+
require 'active_report/base'
|
|
8
|
+
|
|
9
|
+
%w{ controllers }.each do |dir|
|
|
10
|
+
path = File.join(File.dirname(__FILE__), 'app', dir)
|
|
11
|
+
|
|
12
|
+
$LOAD_PATH << path
|
|
13
|
+
ActiveSupport::Dependencies.load_paths << path
|
|
14
|
+
ActiveSupport::Dependencies.load_once_paths.delete(path)
|
|
15
|
+
end
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
module ActiveReport
|
|
2
|
+
|
|
3
|
+
# Special form of a hash that responds to methods if the method is a key in
|
|
4
|
+
# the entry. Also allows passing a hash as the argement to +new+ to allow for
|
|
5
|
+
# initialization of the +HashEntry+.
|
|
6
|
+
#
|
|
7
|
+
# *Note*: This means you should not have keys whose name is the name of an
|
|
8
|
+
# existing +Hash+ method.
|
|
9
|
+
class HashEntry < Hash
|
|
10
|
+
def initialize(hash = nil)
|
|
11
|
+
super
|
|
12
|
+
|
|
13
|
+
self.update(hash) unless has.nil?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def method_missing(symbol, *args, &block)
|
|
17
|
+
if self[symbol]
|
|
18
|
+
self[symbol]
|
|
19
|
+
else
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def respond_to?(symbol, include_private = false)
|
|
25
|
+
if self[symbol]
|
|
26
|
+
true
|
|
27
|
+
else
|
|
28
|
+
super
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end # Class HashEntry
|
|
33
|
+
|
|
34
|
+
# An Entry class designed to store the sign on the entry for easier
|
|
35
|
+
# manipulation of the stored object.
|
|
36
|
+
class SignedEntry
|
|
37
|
+
attr_accessor :object, :sign
|
|
38
|
+
|
|
39
|
+
# Creates a new SignedEntry. The sign parameter defaults to
|
|
40
|
+
# <tt>:positive</tt> but accepts any object. If one of the following
|
|
41
|
+
# values are entered for the sign, the sign is automatically
|
|
42
|
+
# converted to a <tt>1</tt> or <tt>-1</tt> depending upon the value
|
|
43
|
+
# entered.
|
|
44
|
+
#
|
|
45
|
+
# * <tt>true</tt>
|
|
46
|
+
# * <tt>false</tt>
|
|
47
|
+
# * <tt>:true, :positive</tt>
|
|
48
|
+
# * <tt>:false, :negative</tt>
|
|
49
|
+
# * <tt>"true", "positive"</tt>
|
|
50
|
+
# * <tt>"false", "negative"</tt>
|
|
51
|
+
def initialize(object = nil, sign = :positive)
|
|
52
|
+
@object = object
|
|
53
|
+
|
|
54
|
+
@sign = case
|
|
55
|
+
when sign.to_s.eql?("true") then 1
|
|
56
|
+
when sign.to_s.eql?("false") then -1
|
|
57
|
+
when sign.to_s.eql?("positive") then 1
|
|
58
|
+
when sign.to_s.eql?("negative") then -1
|
|
59
|
+
else sign
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Returns true if the sign is greater than or equal to 0.
|
|
64
|
+
#
|
|
65
|
+
# This method is aliased as credit?.
|
|
66
|
+
def positive?
|
|
67
|
+
@sign >= 0
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
alias_method :credit?, :positive?
|
|
71
|
+
|
|
72
|
+
# Returns true if the sign is less than 0.
|
|
73
|
+
#
|
|
74
|
+
# This method is aliased as debit?.
|
|
75
|
+
def negative?
|
|
76
|
+
@sign < 0
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
alias_method :debit?, :negative?
|
|
80
|
+
end # Class SignedEntry
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Active Report objects define how to build a particular report and all required
|
|
84
|
+
# information. Unlike Active Record objects, Active Reports are not saved to nor
|
|
85
|
+
# retrieved from a database, but rather aggregate data from existing Active Record
|
|
86
|
+
# objects (or any other means required).
|
|
87
|
+
#
|
|
88
|
+
# == Creation
|
|
89
|
+
#
|
|
90
|
+
# Active Reports offer many helper methods to assist in creation. For instance, you
|
|
91
|
+
# can specify any number of attributes with the define_attributes method. These
|
|
92
|
+
# attributes will be available to the rest of the class and will be populated with
|
|
93
|
+
# any values that were passed to the +new+ method.
|
|
94
|
+
#
|
|
95
|
+
# class JobReport < ActiveReport::Base
|
|
96
|
+
# define_attribute :jobNumber
|
|
97
|
+
#
|
|
98
|
+
# validates_presence_of :jobNumber
|
|
99
|
+
#
|
|
100
|
+
# def build_report
|
|
101
|
+
# entries = Job.find_all_by_jobNumber(self.jobNumber)
|
|
102
|
+
# end
|
|
103
|
+
# end
|
|
104
|
+
#
|
|
105
|
+
# Alternatively, you could use an ActiveReport::HashEntry or simple +Hash+.
|
|
106
|
+
#
|
|
107
|
+
# class TestReport < ActiveReport::Base
|
|
108
|
+
# def build_report
|
|
109
|
+
# (1..5).each { |i| entries.add(ActiveReport::HashEntry.new( :i => i, :name => 'Topher' )) }
|
|
110
|
+
# end
|
|
111
|
+
# end
|
|
112
|
+
#
|
|
113
|
+
# class TestReport < ActiveReport::Base
|
|
114
|
+
# def build_report
|
|
115
|
+
# (1..5).each { |i| entries.add({ :i => i, :name => 'Topher' }) }
|
|
116
|
+
# end
|
|
117
|
+
# end
|
|
118
|
+
#
|
|
119
|
+
# == Reporting
|
|
120
|
+
#
|
|
121
|
+
# Generating reports is incredibly easy. The following example shows basic usage
|
|
122
|
+
# assuming that +Job+ is a class extending +ActiveRecord::Base+.
|
|
123
|
+
#
|
|
124
|
+
# Job.create( :id => 1, :jobNumber => 123456, :company => "Apple Inc." )
|
|
125
|
+
# Job.create( :id => 2, :jobNumber => 123456, :company => "37signals" )
|
|
126
|
+
#
|
|
127
|
+
# params = {}
|
|
128
|
+
# params[:jobNumber] = 123456
|
|
129
|
+
#
|
|
130
|
+
# report = JobReport.new(params)
|
|
131
|
+
#
|
|
132
|
+
# if report.generate
|
|
133
|
+
# report.entries.each { |e| puts "#{e.id}: Job ##{e.jobNumber} for #{e.company}" }
|
|
134
|
+
# end
|
|
135
|
+
#
|
|
136
|
+
# # => 1: Job #123456 for Apple Inc.
|
|
137
|
+
# 2: Job #123456 for 37signals
|
|
138
|
+
class Base
|
|
139
|
+
include Enumerable
|
|
140
|
+
include ActiveSupport::Callbacks
|
|
141
|
+
include ActiveReport::Validations
|
|
142
|
+
|
|
143
|
+
define_callbacks :before_initialize, :after_initialize
|
|
144
|
+
define_callbacks :before_build_report, :after_build_report
|
|
145
|
+
define_callbacks :before_validate, :validate, :after_validate
|
|
146
|
+
|
|
147
|
+
attr_accessor :id, :params, :errors, :entries
|
|
148
|
+
|
|
149
|
+
# Sets up all parameters including mulit-parameters-attributes. Sets the id of the
|
|
150
|
+
# report to be the current +Time+ as an integer of the +strftime+ format
|
|
151
|
+
# +"%Y%m%d%H%M%S"+.
|
|
152
|
+
def initialize(params = {})
|
|
153
|
+
@params = setup_parameters(params)
|
|
154
|
+
|
|
155
|
+
run_callbacks(:before_initialize)
|
|
156
|
+
|
|
157
|
+
@id = Time.now.strftime("%Y%m%d%H%M%S").to_i
|
|
158
|
+
|
|
159
|
+
@errors = ActiveReport::Errors.new
|
|
160
|
+
@entries = []
|
|
161
|
+
|
|
162
|
+
run_callbacks(:after_initialize)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
private
|
|
166
|
+
|
|
167
|
+
def setup_parameters(params = {})
|
|
168
|
+
new_params = {}
|
|
169
|
+
multi_parameter_attributes = []
|
|
170
|
+
|
|
171
|
+
params.each do |k,v|
|
|
172
|
+
if k.to_s.include?("(")
|
|
173
|
+
multi_parameter_attributes << [ k.to_s, v ]
|
|
174
|
+
else
|
|
175
|
+
new_params[k.to_s] = v
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
new_params.merge(assign_multiparameter_attributes(multi_parameter_attributes))
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Very simplified version of the ActiveRecord::Base method that handles only dates/times
|
|
183
|
+
def execute_callstack_for_multiparameter_attributes(callstack)
|
|
184
|
+
attributes = {}
|
|
185
|
+
|
|
186
|
+
callstack.each do |name, values|
|
|
187
|
+
|
|
188
|
+
if values.empty?
|
|
189
|
+
send(name + '=', nil)
|
|
190
|
+
else
|
|
191
|
+
value = case values.size
|
|
192
|
+
when 2 then t = Time.new; Time.local(t.year, t.month, t.day, values[0], values[min], 0, 0)
|
|
193
|
+
when 5 then t = Time.time_with_datetime_fallback(:local, *values)
|
|
194
|
+
when 3 then Date.new(*values)
|
|
195
|
+
else nil
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
attributes[name.to_s] = value
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
attributes
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Note, the following private methods are copied (almost) directly from ActiveRecord::Base 2.3.3
|
|
207
|
+
|
|
208
|
+
def assign_multiparameter_attributes(pairs)
|
|
209
|
+
execute_callstack_for_multiparameter_attributes( extract_callstack_for_multiparameter_attributes(pairs) )
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def extract_callstack_for_multiparameter_attributes(pairs)
|
|
213
|
+
attributes = { }
|
|
214
|
+
|
|
215
|
+
for pair in pairs
|
|
216
|
+
multiparameter_name, value = pair
|
|
217
|
+
attribute_name = multiparameter_name.split("(").first
|
|
218
|
+
attributes[attribute_name] = [] unless attributes.include?(attribute_name)
|
|
219
|
+
|
|
220
|
+
unless value.empty?
|
|
221
|
+
attributes[attribute_name] <<
|
|
222
|
+
[ find_parameter_position(multiparameter_name), type_cast_attribute_value(multiparameter_name, value) ]
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
attributes.each { |name, values| attributes[name] = values.sort_by{ |v| v.first }.collect { |v| v.last } }
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def type_cast_attribute_value(multiparameter_name, value)
|
|
230
|
+
multiparameter_name =~ /\([0-9]*([a-z])\)/ ? value.send("to_" + $1) : value
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def find_parameter_position(multiparameter_name)
|
|
234
|
+
multiparameter_name.scan(/\(([0-9]*).*\)/).first.first
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
public
|
|
238
|
+
|
|
239
|
+
# Generates the report by calling +build_report+ and runs validation if requested.
|
|
240
|
+
# Calls +before_build_report+ at the beginning and +after_build_report+ at the end
|
|
241
|
+
# and returns the report against which this method was run.
|
|
242
|
+
def generate(perform_validation = true)
|
|
243
|
+
return false if perform_validation and not self.valid?
|
|
244
|
+
|
|
245
|
+
run_callbacks(:before_build_report)
|
|
246
|
+
send(:build_report) if self.respond_to? :build_report
|
|
247
|
+
run_callbacks(:after_build_report)
|
|
248
|
+
|
|
249
|
+
self
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Runs +before_validate+, +validate+ and +after_validate+ and returns
|
|
253
|
+
# true if there were no errors, false otherwise.
|
|
254
|
+
def valid?
|
|
255
|
+
run_callbacks(:before_validate)
|
|
256
|
+
|
|
257
|
+
@errors = ActiveReport::Errors.new
|
|
258
|
+
|
|
259
|
+
run_callbacks(:validate)
|
|
260
|
+
run_callbacks(:after_validate)
|
|
261
|
+
|
|
262
|
+
@errors.empty?
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Defined to always return true since no data actually gets saved to the database.
|
|
266
|
+
# This is necessary for the +form_for+ methods in
|
|
267
|
+
# +ActionView::Helpers::FormHelper+ to work properly.
|
|
268
|
+
def new_record?
|
|
269
|
+
true
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Override this method to allow for exporting to a csv file.
|
|
273
|
+
#
|
|
274
|
+
# Example:
|
|
275
|
+
#
|
|
276
|
+
# def to_csv
|
|
277
|
+
# FasterCSV.generate do |csv|
|
|
278
|
+
# csv << [ 'Name', 'Date' ]
|
|
279
|
+
#
|
|
280
|
+
# @entries.each do |e|
|
|
281
|
+
# csv << [ e.name, e.created_at ]
|
|
282
|
+
# end
|
|
283
|
+
# end
|
|
284
|
+
# end
|
|
285
|
+
def to_csv
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
protected
|
|
289
|
+
# Helper method to easily define new attributes. For example, the following
|
|
290
|
+
#
|
|
291
|
+
# class TestReport < ActiveReport::Base
|
|
292
|
+
# define_attributes :jobNumber, :jobStage
|
|
293
|
+
# end
|
|
294
|
+
#
|
|
295
|
+
# is equivalent to
|
|
296
|
+
#
|
|
297
|
+
# class TestReport < ActiveReport::Base
|
|
298
|
+
# attr_accessor :jobNumber, :jobStage
|
|
299
|
+
#
|
|
300
|
+
# def intialize(params = {})
|
|
301
|
+
# super
|
|
302
|
+
#
|
|
303
|
+
# @jobNumber = params["jobNumber"]
|
|
304
|
+
# @jobStage = params["jobStage"]
|
|
305
|
+
# end
|
|
306
|
+
# end
|
|
307
|
+
#
|
|
308
|
+
# Accepts multiple attributes and is also aliased as +define_attribute+.
|
|
309
|
+
def self.define_attributes(*attribs)
|
|
310
|
+
return if attribs.nil?
|
|
311
|
+
|
|
312
|
+
send(:before_initialize) do |report|
|
|
313
|
+
attribs.each do |attrib|
|
|
314
|
+
report.class.instance_eval "attr_accessor :#{attrib.to_s}"
|
|
315
|
+
|
|
316
|
+
report.instance_eval("@#{attrib.to_s} = params['#{attrib.to_s}'] unless params.blank?")
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
class << self
|
|
322
|
+
alias_method :define_attribute, :define_attributes
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# Callback run immediately before +build_report+.
|
|
326
|
+
def before_build_report
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# Override this to builds the report and all entries.
|
|
330
|
+
def build_report
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Callback run immediately after +build_report+.
|
|
334
|
+
def after_build_report
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Callback run immediately before +validate+.
|
|
338
|
+
def before_validate
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Overwrite this method for validation checks on generation of report
|
|
342
|
+
# and use +Errors.add(message)+ for invalid attributes.
|
|
343
|
+
def validate
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# Callback run immediately after +validate+.
|
|
347
|
+
def after_validate
|
|
348
|
+
end
|
|
349
|
+
end # Class Base
|
|
350
|
+
|
|
351
|
+
end # Module ActiveReport
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Array.class_eval do
|
|
2
|
+
|
|
3
|
+
def count
|
|
4
|
+
size # Temporary fix because I can't upgrade the version of ruby on wildcat
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
alias_method :add, :<<
|
|
8
|
+
end unless Array.new.respond_to? :add
|
|
9
|
+
|
|
10
|
+
Object.class_eval do
|
|
11
|
+
def self.alias_class_method(new_name, old_name)
|
|
12
|
+
meta = class << self; self; end
|
|
13
|
+
meta.send :alias_method, new_name, old_name
|
|
14
|
+
end
|
|
15
|
+
end unless Object.respond_to? :alias_class_method
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module ActiveReport
|
|
2
|
+
|
|
3
|
+
module Validations
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.extend ClassMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
|
|
10
|
+
# Ensures that the requested parameters exist and are not empty.
|
|
11
|
+
#
|
|
12
|
+
# class TestReport < ActiveReport::Base
|
|
13
|
+
# validates_presence_of :jobNumber
|
|
14
|
+
# end
|
|
15
|
+
def validates_presence_of(*params)
|
|
16
|
+
return if params.nil?
|
|
17
|
+
|
|
18
|
+
send(:validate) do |report|
|
|
19
|
+
params.each do |param|
|
|
20
|
+
field = report.params[param.to_s]
|
|
21
|
+
|
|
22
|
+
if field.blank?
|
|
23
|
+
report.errors.add "#{param} must be defined"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end # Module ClassMethods
|
|
30
|
+
|
|
31
|
+
end # Module Validations
|
|
32
|
+
|
|
33
|
+
end # Module ActiveReport
|
data/rails/init.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class ActiveReportTest < ActiveSupport::TestCase
|
|
4
|
+
test "Errors properly extends Array" do
|
|
5
|
+
assert ActiveReport::Errors.new.respond_to? :add
|
|
6
|
+
assert ActiveReport::Errors.new.respond_to? :full_messages
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
test "HashEntry propperly extends Hash" do
|
|
10
|
+
entry = ActiveReport::HashEntry.new(:jobNumber => 123)
|
|
11
|
+
|
|
12
|
+
assert (entry.respond_to? :jobNumber)
|
|
13
|
+
assert entry.jobNumber == 123
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
test "class can extend base" do
|
|
17
|
+
class TestReport < ActiveReport::Base
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
t = TestReport.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
test "class can build report" do
|
|
24
|
+
t = SimpleTestReport.new
|
|
25
|
+
t.generate
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
test "class can call basic functions" do
|
|
29
|
+
params = {}
|
|
30
|
+
params[:jobNumber] = 123456
|
|
31
|
+
|
|
32
|
+
t = BasicTestReport.new(params)
|
|
33
|
+
t.generate
|
|
34
|
+
|
|
35
|
+
t.entries.each do |entry|
|
|
36
|
+
assert entry.jobNumber == params[:jobNumber]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class CoreExtentionTest < ActiveSupport::TestCase
|
|
4
|
+
test "array responds to add" do
|
|
5
|
+
assert Array.new.respond_to? :add
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
test "object responds to alias_class_method" do
|
|
9
|
+
assert Object.respond_to? :alias_class_method
|
|
10
|
+
|
|
11
|
+
Object.alias_class_method :aliased_to_s, :to_s
|
|
12
|
+
|
|
13
|
+
assert Object.respond_to? :aliased_to_s
|
|
14
|
+
end
|
|
15
|
+
end
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
ENV['RAILS_ENV'] = 'test'
|
|
2
|
+
ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '../../../../..'
|
|
3
|
+
|
|
4
|
+
require 'rubygems'
|
|
5
|
+
require 'active_support'
|
|
6
|
+
require 'active_support/test_case'
|
|
7
|
+
|
|
8
|
+
require 'test/unit'
|
|
9
|
+
|
|
10
|
+
require 'active_report'
|
|
11
|
+
|
|
12
|
+
class SimpleTestReport < ActiveReport::Base
|
|
13
|
+
def build_report
|
|
14
|
+
entries.add(ActiveReport::HashEntry.new( :first_name => "Topher", :last_name => "Fangio" ))
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class BasicTestReport < ActiveReport::Base
|
|
19
|
+
define_attribute :jobNumber
|
|
20
|
+
validates_presence_of :jobNumber
|
|
21
|
+
|
|
22
|
+
def build_report
|
|
23
|
+
entries.add(ActiveReport::HashEntry.new( :jobNumber => @jobNumber ))
|
|
24
|
+
end
|
|
25
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: topherfangio-active_report
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Topher Fangio
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2009-06-18 00:00:00 -07:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies: []
|
|
15
|
+
|
|
16
|
+
description:
|
|
17
|
+
email: fangiotophia@gmail.com
|
|
18
|
+
executables: []
|
|
19
|
+
|
|
20
|
+
extensions: []
|
|
21
|
+
|
|
22
|
+
extra_rdoc_files:
|
|
23
|
+
- README.rdoc
|
|
24
|
+
files:
|
|
25
|
+
- .document
|
|
26
|
+
- .gitignore
|
|
27
|
+
- MIT-LICENSE
|
|
28
|
+
- README.rdoc
|
|
29
|
+
- Rakefile
|
|
30
|
+
- VERSION
|
|
31
|
+
- active_report.gemspec
|
|
32
|
+
- generators/active_report/USAGE
|
|
33
|
+
- generators/active_report/active_report_generator.rb
|
|
34
|
+
- generators/active_report/templates/controller.rb
|
|
35
|
+
- generators/active_report/templates/create.html.erb
|
|
36
|
+
- generators/active_report/templates/model.rb
|
|
37
|
+
- generators/active_report/templates/new.html.erb
|
|
38
|
+
- generators/active_reports_controller/USAGE
|
|
39
|
+
- generators/active_reports_controller/active_reports_controller_generator.rb
|
|
40
|
+
- generators/active_reports_controller/templates/active_reports_controller.rb
|
|
41
|
+
- lib/active_report.rb
|
|
42
|
+
- lib/active_report/base.rb
|
|
43
|
+
- lib/active_report/core_extention.rb
|
|
44
|
+
- lib/active_report/errors.rb
|
|
45
|
+
- lib/active_report/validations.rb
|
|
46
|
+
- rails/init.rb
|
|
47
|
+
- tasks/active_report_tasks.rake
|
|
48
|
+
- test/active_report_test.rb
|
|
49
|
+
- test/core_extention_test.rb
|
|
50
|
+
- test/test_helper.rb
|
|
51
|
+
has_rdoc: true
|
|
52
|
+
homepage: http://github.com/topherfangio/active_report
|
|
53
|
+
post_install_message:
|
|
54
|
+
rdoc_options:
|
|
55
|
+
- --charset=UTF-8
|
|
56
|
+
require_paths:
|
|
57
|
+
- lib
|
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: "0"
|
|
63
|
+
version:
|
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: "0"
|
|
69
|
+
version:
|
|
70
|
+
requirements: []
|
|
71
|
+
|
|
72
|
+
rubyforge_project:
|
|
73
|
+
rubygems_version: 1.2.0
|
|
74
|
+
signing_key:
|
|
75
|
+
specification_version: 2
|
|
76
|
+
summary: ActiveReport enables you to easily generate reports.
|
|
77
|
+
test_files:
|
|
78
|
+
- test/test_helper.rb
|
|
79
|
+
- test/core_extention_test.rb
|
|
80
|
+
- test/active_report_test.rb
|