topherfangio-active_report 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|