acts_as_xls 1.0.0

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/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
+