acts_as_xls 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rails", "3.0.9"
4
+ gem "spreadsheet"
5
+ gem "axlsx"
6
+
7
+ group :development, :test do
8
+ gem "capybara", ">= 0.4.0"
9
+ gem "sqlite3"
10
+ gem "ruby-debug"
11
+ end
12
+
13
+ gemspec
14
+
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
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,86 @@
1
+ = ActsAsXls
2
+
3
+ the gem add support for xls, xlsx file generation
4
+
5
+ ==Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'acts_as_xls'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install acts_as_xls
18
+
19
+
20
+ ==Usage
21
+ ===Controler
22
+ in your controller you can write a render like this:
23
+
24
+ #app/controllers/users_controller.rb
25
+ def index
26
+ @users = User.all
27
+
28
+ respond_do |format
29
+ format.xls { render :xls => "index"}
30
+ format.xlsx { render :xlsx => "index"}
31
+ end
32
+ end
33
+
34
+ or if you need a quick render, without any template you can write:
35
+ ...
36
+ format.xls { render :xls => @users}
37
+
38
+ the renderer will call to_xls method to the @users and return the file
39
+
40
+ Note: if you use render :xlsx => @users you have to implement your own to_xlsx method.
41
+
42
+ ===Views
43
+ you have to create a template in your views folder for xls and xlsx:
44
+
45
+ xls template expose the book variable, you can use as explained in Spreadsheet guide (http://spreadsheet.rubyforge.org/GUIDE_txt.html)
46
+
47
+ #app/views/users/index.xls.maker
48
+ sheet1 = book.create_worksheet
49
+ sheet1.name = 'My First Worksheet'
50
+ x = 0
51
+ @user.each {|user| sheet1.row(x + 1).concat [user.name, user.age]}
52
+
53
+ and for xlsx the template expose the package variable you can use as described in Axlsx site http://axlsx.blogspot.it/
54
+
55
+ #app/views/users/index.xlsx.maker
56
+ package.workbook do |wb|
57
+ wb.add_worksheet do |sheet|
58
+ @users.each { |user| sheet.add_row [user.name, user.age]}
59
+ end
60
+ end
61
+
62
+ then in your view simply link the page using the right format:
63
+
64
+ #app/views/users/index.html.erb
65
+ <%= link_to "xls", users_path(:format => :xls) %>
66
+ <%= link_to "xlsx", users_path(:format => :xlsx) %>
67
+
68
+ ===Options
69
+ You can pass all renderers common options, plus :filename => "my_file_name.xls" | "my_file_name.xlsx" to change the default filename (file.xls or file.xlsx)
70
+
71
+ ==Examples
72
+ You can watch the test/dummy application to find some working examples
73
+
74
+ ==Contributing
75
+
76
+ 1. Fork it
77
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
78
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
79
+ 4. Push to the branch (`git push origin my-new-feature`)
80
+ 5. Create new Pull Request
81
+
82
+ ==Thanks
83
+ I want to thanks:
84
+ - Daniel J. Berger, Hannes Wyss, GmbH, creators of the Spreadsheet gem that is the engine of the xls extension
85
+ - randym, creator of the Axlsx gem that powers the xlsx extension ( https://github.com/randym/axlsx )
86
+
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ begin
4
+ require 'bundler/setup'
5
+ require "bundler/gem_tasks"
6
+ rescue LoadError
7
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
8
+ end
9
+
10
+ require 'rake'
11
+ require 'rake/testtask'
12
+
13
+ #require 'rake/rdoctask'
14
+ require 'rdoc/task'
15
+
16
+
17
+
18
+ Rake::TestTask.new(:test) do |t|
19
+ t.libs << 'lib'
20
+ t.libs << 'test'
21
+ t.pattern = 'test/**/*_test.rb'
22
+ t.verbose = false
23
+ end
24
+
25
+ task :default => :test
26
+
27
+ Rake::RDocTask.new(:rdoc) do |rdoc|
28
+ rdoc.rdoc_dir = 'rdoc'
29
+ rdoc.title = 'ActsAsXls'
30
+ rdoc.options << '--line-numbers' << '--inline-source'
31
+ rdoc.rdoc_files.include('README.rdoc')
32
+ rdoc.rdoc_files.include('lib/**/*.rb')
33
+ end
@@ -0,0 +1,41 @@
1
+ require "acts_as_xls/xls"
2
+
3
+ module ActsAsXls
4
+ module Base
5
+ def self.included(base) # :nodoc:
6
+ base.send :extend, ClassMethods
7
+ base.send :include, InstanceMethods
8
+ end
9
+
10
+ #Instance methods for the mixin
11
+ module InstanceMethods
12
+
13
+ def to_xls(options = {})
14
+ ActsAsXls::Xls.to_xls(self,options)
15
+ end
16
+ end
17
+
18
+ #ToDo
19
+ #* to_xlsx
20
+ #* to_pdf
21
+
22
+ # Class methods for the mixin
23
+ module ClassMethods
24
+
25
+ def new_from_xls(options = {})
26
+ ActsAsXls::Xls.new_from_xls(self,options)
27
+ end
28
+
29
+ #ToDo
30
+ #* new_from_xlsx
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
38
+ require 'active_record'
39
+ ActiveRecord::Base.send :include, ActsAsXls::Base
40
+ ActiveRecord::Relation.send :include, ActsAsXls::Base
41
+ Array.send :include, ActsAsXls::Base
@@ -0,0 +1,17 @@
1
+ module ActsAsXls
2
+ class Engine < Rails::Engine
3
+
4
+ #initializer 'usefull_table.helper' do |app|
5
+ # ActiveSupport.on_load(:action_controller) do
6
+ # include UsefullTableHelper
7
+ # end
8
+ # ActiveSupport.on_load(:action_view) do
9
+ # include UsefullTableHelper
10
+ # end
11
+ #
12
+ #end
13
+ end
14
+ end
15
+
16
+ require "acts_as_xls/renderer"
17
+ require "acts_as_xls/base"
@@ -0,0 +1,15 @@
1
+ module ActsAsXls
2
+ class CustomError < StandardError
3
+ def initialize(*args)
4
+ @options = args.extract_options!
5
+ super
6
+ end
7
+
8
+ def message
9
+ I18n.t("#{self.class.name.gsub(/::/,'.')}", @options)
10
+ end
11
+ end
12
+
13
+
14
+ end
15
+
@@ -0,0 +1,100 @@
1
+ require "action_controller"
2
+ require "action_view/template"
3
+
4
+ Mime::Type.register("application/vnd.ms-excel", :xls) unless Mime::Type.lookup_by_extension(:xls)
5
+ Mime::Type.register("application/vnd.openxmlformats", :xlsx) unless Mime::Type.lookup_by_extension(:xlsx)
6
+ #Mime::Type.register("application/pdf", :pdf) unless Mime::Type.lookup_by_extension(:pdf)
7
+
8
+ #Renderers try to render obj.to_xls
9
+ #then look for *.xls.maker template to render
10
+ ActionController::Renderers.add :xls do |obj, options|
11
+ options ||= {}
12
+ filename = options[:filename] || "file.xls"
13
+ #Rails::logger.info("Renderer(xls) options=#{options.inspect}, obj=#{obj.inspect}")
14
+ if obj.respond_to?(:to_xls)
15
+ #No template, must render obj
16
+ send_data obj.to_xls, :type => Mime::XLS, :filename => filename
17
+ else
18
+ send_file render_to_string(options[:template]), :type => Mime::XLS, :disposition => "attachment; filename=#{filename}"
19
+ end
20
+
21
+ end
22
+
23
+ #Renderers try to render obj.to_xlsx
24
+ #then look for *.xlsx.maker template to render
25
+ ActionController::Renderers.add :xlsx do |obj, options|
26
+ options ||= {}
27
+ filename = options[:filename] || "file.xlsx"
28
+ #Rails::logger.info("Renderer(xlsx) options=#{options.inspect}, obj=#{obj.inspect}")
29
+ if obj.respond_to?(:to_xlsx)
30
+ #No template, must render obj
31
+ send_data obj.to_xlsx, :type => Mime::XLSX, :filename => filename
32
+ else
33
+ #Rails::logger.info("Renderer path=#{path}")
34
+ send_file render_to_string(options[:template]), :type => Mime::XLSX, :disposition => "attachment; filename=#{filename}"
35
+ end
36
+ end
37
+
38
+ #~ ActionController::Renderers.add :pdf do |obj, options|
39
+ #~ options ||= {}
40
+ #~ filename = options[:filename] || "file.pdf"
41
+ #~ #Rails::logger.info("Renderer(xlsx) options=#{options.inspect}, obj=#{obj.inspect}")
42
+ #~ if obj.respond_to?(:to_pdf)
43
+ #~ #No template, must render obj
44
+ #~ send_data obj.to_xlsx, :type => Mime::PDF, :filename => filename
45
+ #~ else
46
+ #~ #Rails::logger.info("Renderer path=#{path}")
47
+ #~ send_file render_to_string(options[:template]), :type => Mime::PDF, :disposition => "attachment; filename=#{filename}"
48
+ #~ end
49
+ #~ end
50
+
51
+ module ActsAsXls
52
+ #Render a template like *.[xls|xlsx].maker
53
+ #the template is evaluated as a ruby expression.
54
+ #you can use package (xlsx) or book (xls) inside the template to create an excel file
55
+ #template return tempfile path tha is rendered by the renderer.
56
+ module MAKER
57
+
58
+ def self.call(template)
59
+ %(extend #{Proxy}; #{template.source}; render)
60
+ end
61
+
62
+ module Proxy
63
+ def book
64
+ Spreadsheet.client_encoding = 'UTF-8'
65
+ @book ||= Spreadsheet::Workbook.new
66
+ end
67
+
68
+ def render_book
69
+ @book.write @temp.path if @book
70
+ end
71
+
72
+ def package
73
+ @package ||= Axlsx::Package.new
74
+ end
75
+
76
+ def render_package
77
+ @package.serialize @temp.path if @package
78
+ end
79
+
80
+
81
+ #~ def pdf
82
+ #~ @pdf ||= Prawn::Document.new(:page_size => "A4", :margin => [10.28,10,10,10])
83
+ #~ end
84
+
85
+ #Renders all methods starting form render_
86
+ #this solution permits to extend che module adding new extesnions and renderers
87
+ def render
88
+ @temp = Tempfile.new("tmp")
89
+ renderers = self.methods.select {|method| method.match(/^render_.*/)}
90
+ Rails::logger.info("ActsAsXls::MAKER::Proxy renderers=#{renderers.inspect}")
91
+ renderers.each {|r| eval(r)}
92
+ @temp.path
93
+ end
94
+ end
95
+
96
+ end
97
+ end
98
+
99
+
100
+ ActionView::Template.register_template_handler :maker, ActsAsXls::MAKER
@@ -0,0 +1,4 @@
1
+ module ActsAsXls
2
+ VERSION = "1.0.0"
3
+ end
4
+
@@ -0,0 +1,165 @@
1
+ module ActsAsXls
2
+ module Xls
3
+ class << self
4
+ def new_from_xls(base, *args)
5
+ base.inspect
6
+ end
7
+
8
+ def to_xls(base_instance, *args, &block)
9
+ #Rails::logger.info("Array#to_xls dentro")
10
+ options = args.extract_options!
11
+
12
+ if base_instance.kind_of?(ActiveRecord::Base)
13
+ #Single ActiveRecord record
14
+ return to_xls_from_activerecord(base_instance, *(args << options), &block) if base_instance.kind_of?(ActiveRecord::Base)
15
+ elsif base_instance.kind_of?(Array) || base_instance.kind_of?(ActiveRecord::Relation)
16
+ #Array of Array or Array of ActiveRecord
17
+ return to_xls_from_activerecord(nil, *(args << options.merge!({:prepend => base_instance})), &block) if base_instance.first.kind_of?(Array)
18
+ return to_xls_from_activerecord(base_instance, *(args << options), &block) if base_instance.first.kind_of?(ActiveRecord::Base)
19
+ else
20
+ "UnknownType"
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+
27
+ #==Usage
28
+ # $ Item.all.to_xlsLa classe restituisce un excel
29
+ #
30
+ #Return a binary string of excel with columns title (humanize columns name) and a row for each record
31
+ #Columns name are used as method to render cell values:
32
+ # column_name = name => cell_value = @item.name
33
+ # column_name = user.name => cell_value = @item.user.name
34
+ #
35
+ #==Options
36
+ # :only => [...] #List of columns to render
37
+ # :except => [...] #List of columns not to render (must be in humanized form)
38
+ # :header => true #Add columns name as title
39
+ # :header_columns => ["col1", "col2", ..] #Set columns name
40
+ # :human => true #Humanize columns name using ActiveRecord Localization
41
+ # :worksheet => "Foglio1" #worksheet name
42
+ # :file => true #Return a Filetmp instead of a StringIO
43
+ # :prepend => [["Col 0, Row 0", "Col 1, Row 0"], ["Col 0, Row 1"]]
44
+ # Prepend columns and row passed to excel
45
+ #
46
+ # block |column, value, row_index| ....
47
+ def to_xls_from_activerecord(base_instance, *args, &block)
48
+ options = args.extract_options!
49
+
50
+ return nil if empty?(base_instance) && options[:prepend].blank?
51
+
52
+ #Rails::logger.info("Array#to_xls_from_activerecord(1) dopo primo return")
53
+
54
+ columns = []
55
+ options.reverse_merge!(:header => true)
56
+ options[:human] ||= true
57
+ options[:worksheet] ||= "Foglio1"
58
+ xls_report = StringIO.new
59
+ book = Spreadsheet::Workbook.new
60
+ sheet = book.create_worksheet
61
+ sheet.name = options[:worksheet]
62
+
63
+ sheet_index = 0
64
+
65
+ unless options[:prepend].blank?
66
+ options[:prepend].each do |array|
67
+ sheet.row(sheet_index).concat(array)
68
+ sheet_index += 1
69
+ end
70
+ end
71
+
72
+ unless empty?(base_instance)
73
+
74
+ base_instance = base_instance.to_a
75
+
76
+
77
+ #Must check culumns name agains methids and removing the non working
78
+ if options[:only]
79
+ #columns = Array(options[:only]).map(&:to_sym)
80
+ columns = Array(options[:only]).map { |column| validate(column,base_instance)}
81
+ columns.compact!
82
+ else
83
+ columns = base_instance.first.class.column_names.map(&:to_sym) - Array(options[:except]).map(&:to_sym)
84
+ end
85
+
86
+ #Humanize columns name
87
+ options[:header_columns] ||= columns.map do |column|
88
+ #Se :human => false non umanizzo i nomi
89
+ #Iconve risolve i problemi di codifica su caratteri strani tipo � che diventa \340....
90
+ options[:human] == false ? column.to_s : Iconv.conv("UTF-8", "LATIN1", base_instance.first.class.human_attribute_name(column.to_s.gsub(/\./,"_")))
91
+ end
92
+
93
+ return nil if columns.empty? && options[:prepend].blank?
94
+
95
+ #Add headers to excel
96
+ if options[:header]
97
+ sheet.row(sheet_index).concat(options[:header_columns])
98
+ sheet_index += 1
99
+ end
100
+
101
+ base_instance.each_with_index do |obj, index|
102
+ if block
103
+ sheet.row(sheet_index).replace(columns.map { |column| block.call(column, get_column_value(obj, column), index) })
104
+ else
105
+ sheet.row(sheet_index).replace(columns.map { |column| get_column_value(obj, column) })
106
+ end
107
+
108
+ sheet_index += 1
109
+ end
110
+ end
111
+
112
+ #Rails::logger.info("Spreadsheet::Workbook sheet.rows=#{sheet.rows.inspect}")
113
+ #Rails::logger.info("Spreadsheet::Workbook book=#{book.inspect}")
114
+ if options[:file] == true
115
+ Rails::logger.info("Spreadsheet::Workbook file")
116
+ tmp = Tempfile.new('tmp_xls')
117
+ book.write(tmp.path)
118
+ tmp
119
+ else
120
+ Rails::logger.info("Spreadsheet::Workbook stringIO")
121
+ book.write(xls_report)
122
+ xls_report.string
123
+ end
124
+ end
125
+
126
+ #Rails::logger.info("Array#to_xls_from_activerecord obj.option=#{options.inspect}, self.inspect=#{self.inspect}")
127
+ #Restituisce il valore della colonna comprese le tabelle collegate
128
+ #Nel caso il valore della tabella collegata sia nullo restiuisce ""
129
+ def get_column_value(obj, column) #:doc:
130
+ if column.to_s.split(".").length > 1
131
+ securize(obj, column) ? obj.instance_eval(column.to_s) : ""
132
+ else
133
+ obj.send(column)
134
+ end
135
+ end
136
+
137
+ def securize(obj, column)
138
+ collection = column.to_s.split(".")
139
+ if collection.length > 1
140
+ collection.pop
141
+ collection = collection.join(".")
142
+ !obj.instance_eval(collection).blank?
143
+ else
144
+ true
145
+ end
146
+ end
147
+
148
+ #Return true if base instance is empty or null
149
+ def empty?(base_instance)
150
+ return true if base_instance.nil?
151
+ return true if base_instance.blank?
152
+ false
153
+ end
154
+
155
+ def validate(column,base_instance)
156
+ base_instance.first.instance_eval("self." + column.to_s)
157
+ column.to_sym
158
+ rescue NoMethodError, RuntimeError
159
+ nil
160
+ end
161
+
162
+
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,9 @@
1
+ module ActsAsXls
2
+ def self.setup
3
+ end
4
+ end
5
+
6
+ require "spreadsheet"
7
+ require "axlsx"
8
+ require "acts_as_xls/engine"
9
+ require "acts_as_xls/exceptions"
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_xls
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Andrea Bignozzi
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-06-29 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Extend Rails capabilities of importing and exporting excel files thanks to Spreadsheet gem
23
+ email:
24
+ - skylord73@gmail.com
25
+ executables: []
26
+
27
+ extensions: []
28
+
29
+ extra_rdoc_files: []
30
+
31
+ files:
32
+ - lib/acts_as_xls.rb
33
+ - lib/acts_as_xls/engine.rb
34
+ - lib/acts_as_xls/xls.rb
35
+ - lib/acts_as_xls/exceptions.rb
36
+ - lib/acts_as_xls/base.rb
37
+ - lib/acts_as_xls/version.rb
38
+ - lib/acts_as_xls/renderer.rb
39
+ - MIT-LICENSE
40
+ - Rakefile
41
+ - Gemfile
42
+ - README.rdoc
43
+ - CHANGELOG.md
44
+ has_rdoc: true
45
+ homepage:
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ hash: 3
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.3.7
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Extend Rails capabilities of importing and exporting excel files
78
+ test_files: []
79
+