Skip to content

Commit

Permalink
Merge tag 'v1.0.6' into feature/upgrade_to_latest_rails_4_3256_lk
Browse files Browse the repository at this point in the history
tag v1.0.6
  • Loading branch information
marklazz committed Mar 2, 2016
2 parents 2007871 + 65968bb commit 263005e
Show file tree
Hide file tree
Showing 23 changed files with 251 additions and 148 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -4,5 +4,6 @@ log/*.log
pkg/
*.gem
Gemfile.lock
spec/gemfiles/*.lock
.ruby-version
.ruby-gemset
16 changes: 11 additions & 5 deletions .travis.yml
@@ -1,8 +1,14 @@
language: ruby
cache: bundler
bundler_args: --path ../../vendor/bundle
rvm:
- 2.0.0
- 2.2.2
- 1.9.3
- jruby-head


script: bundle exec rake spec
- jruby
gemfile:
- spec/gemfiles/Gemfile.rails-3.2
- spec/gemfiles/Gemfile.rails-4.0
- spec/gemfiles/Gemfile.rails-4.1
- spec/gemfiles/Gemfile.rails-4.2
- Gemfile
script: bundle exec rspec
149 changes: 149 additions & 0 deletions README.md
@@ -0,0 +1,149 @@
# to_spreadsheet [![Build Status](https://secure.travis-ci.org/glebm/to_spreadsheet.png?branch=master)](http://travis-ci.org/glebm/to_spreadsheet)

to_spreadsheet lets your Rails 3+ app render Excel files using the existing slim/haml/erb/etc views.

Installation
------------

Add it to your Gemfile:
```ruby
gem 'to_spreadsheet'
```

Usage
-----

In the controller:
```ruby
# my_thingies_controller.rb
class MyThingiesController < ApplicationController
respond_to :xls, :html
def index
@my_items = MyItem.all
respond_to do |format|
format.html
format.xlsx { render xlsx: :index, filename: "my_items_doc" }
end
end
end
```

In the view partial:
```haml
# _my_items.haml
%table
%caption My items
%thead
%tr
%td ID
%td Name
%tbody
- my_items.each do |my_item|
%tr
%td.number= my_item.id
%td= my_item.name
%tfoot
%tr
%td(colspan="2") #{my_items.length}
```

In the XLSX view:
```haml
# index.xls.haml
= render 'my_items', my_items: @my_items
```

In the HTML view:
```haml
# index.html.haml
= link_to 'Download spreadsheet', my_items_url(format: :xlsx)
= render 'my_items', my_items: @my_items
```

### Worksheets

Every table in the view will be converted to a separate sheet.
The sheet title will be assigned to the value of the table’s caption element if it exists.

### Formatting

You can define formats in your view file (local to the view) or in the initializer

```ruby
format_xls 'table.my-table' do
workbook use_autowidth: true
sheet orientation: landscape
format 'th', b: true # bold
format 'tbody tr', bg_color: lambda { |row| 'ddffdd' if row.index.odd? }
format 'A3:B10', i: true # italic
format column: 0, width: 35
format 'td.custom', lambda { |cell| modify cell somehow.}
# default value (fallback value when value is blank or 0 for integer / float)
default 'td.price', 10
end
```

For the full list of supported properties head here: http://rubydoc.info/github/randym/axlsx/Axlsx/Styles#add_style-instance_method
In addition, for column formats, Axlsx columnInfo properties are also supported

### Advanced formatting

to_spreadsheet [associates](https://github.com/glebm/to_spreadsheet/blob/master/lib/to_spreadsheet/renderer.rb#L33) HTML nodes with Axlsx objects as follows:

| HTML tag | Axlsx object |
|----------|--------------|
| table | worksheet |
| tr | row |
| td, th | cell |

For example, to directly manipulate a worksheet:
```ruby
format_xls do
format 'table' do |worksheet|
worksheet.add_chart ...
# to get the associated Nokogiri node:
el = context.to_xml_node(worksheet)
end
end
```

### Themes

You can define themes, i.e. blocks of formatting code:
```ruby
ToSpreadsheet.theme :zebra do
format 'tr', bg_color: lambda { |row| 'ddffdd' if row.index.odd? }
end
```

And then use them:
```ruby
format_xls 'table.zebra', ToSpreadsheet.theme(:zebra)
```

### Using along side axlsx-rails
If you are using [axlsx-rails](https://github.com/straydogstudio/axlsx_rails), :xlsx renderer might have already been defined. In that case define a custome renderer using
```ruby
# app/config/application.rb
config.to_spreadsheet.renderer = :html2xlsx
```

And then in controller
```ruby
respond_to do |format|
format.html2xlsx
end
```

### Types

The default theme uses class names on td/th to cast values.
Here is the list of class to type mapping:

| CSS class | Format |
|------------------|--------------------------|
| decimal or float | Decimal |
| num or int | Integer |
| datetime | DateTime (Chronic.parse) |
| date | Date (Date.parse) |
| time | Time (Chronic.parse) |
116 changes: 0 additions & 116 deletions README.textile

This file was deleted.

9 changes: 9 additions & 0 deletions Rakefile
Expand Up @@ -21,3 +21,12 @@ task :write_test_xlsx => :env do
ToSpreadsheet::Renderer.to_package(html).serialize(path)
puts "Written to #{path}"
end

desc "Test all rails versions"
task :test_all_rails do
Dir.glob("./spec/gemfiles/*{[!.lock]}").each do |gemfile|
puts "TESTING WITH #{gemfile}"
system "BUNDLE_GEMFILE=#{gemfile} bundle | grep Installing"
system "BUNDLE_GEMFILE=#{gemfile} bundle exec rspec"
end
end
6 changes: 5 additions & 1 deletion lib/to_spreadsheet.rb
@@ -1,10 +1,13 @@
require 'to_spreadsheet/version'
require 'to_spreadsheet/context'
require 'to_spreadsheet/renderer'
require 'to_spreadsheet/railtie' if defined?(Rails)

module ToSpreadsheet
class << self
def renderer
@renderer ||= :xlsx
end

def theme(name, &formats)
@themes ||= {}
if formats
Expand All @@ -16,5 +19,6 @@ def theme(name, &formats)
end
end

require 'to_spreadsheet/railtie' if defined?(Rails)
require 'to_spreadsheet/themes/default'
ToSpreadsheet::Context.global.format_xls ToSpreadsheet.theme(:default)
20 changes: 15 additions & 5 deletions lib/to_spreadsheet/rails/action_pack_renderers.rb
@@ -1,10 +1,20 @@
require 'active_support'
require 'action_controller/metal/renderers'
require 'action_controller/metal/responder'

# in rails 3.2 it's ActiveSupport::VERSION
# in rails 4.0+ it's ActiveSupport.version (instance of Gem::Version)
if ActiveSupport.respond_to?(:version) && ActiveSupport.version.to_s >= "4.2.0"
# For rails 4.2
require 'action_controller/responder'
else
# For rails 3.2 - rails 4.1
require 'action_controller/metal/responder'
end


# This will let us do thing like `render :xlsx => 'index'`
# This is similar to how Rails internally implements its :json and :xml renderers
ActionController::Renderers.add :xlsx do |template, options|
ActionController::Renderers.add ToSpreadsheet.renderer do |template, options|
filename = options[:filename] || options[:template] || 'data'
xlsx_options = options.merge(layout: false, formats: [:xlsx, :html])
data = ToSpreadsheet::Context.with_context ToSpreadsheet::Context.global.merge(ToSpreadsheet::Context.new) do |context|
Expand All @@ -15,15 +25,15 @@
end
ToSpreadsheet::Renderer.to_data(html, context)
end
send_data data, type: :xlsx, disposition: %(attachment; filename="#{filename}.xlsx")
send_data data, type: ToSpreadsheet.renderer, disposition: %(attachment; filename="#{filename}.xlsx")
end

class ActionController::Responder
# This sets up a default render call for when you do
# respond_to do |format|
# format.xlsx
# end
def to_xlsx
controller.render xlsx: controller.action_name
define_method "to_#{ToSpreadsheet.renderer}" do
controller.render ToSpreadsheet.renderer => controller.action_name
end
end
2 changes: 1 addition & 1 deletion lib/to_spreadsheet/rails/mime_types.rb
@@ -1,2 +1,2 @@
require 'action_dispatch/http/mime_type'
Mime::Type.register "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", :xlsx unless Mime::Type.lookup_by_extension(:xlsx)
Mime::Type.register "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ToSpreadsheet.renderer unless Mime::Type.lookup_by_extension(ToSpreadsheet.renderer)
13 changes: 9 additions & 4 deletions lib/to_spreadsheet/railtie.rb
@@ -1,10 +1,15 @@
require 'rails/railtie'
require 'to_spreadsheet/rails/mime_types'
require 'to_spreadsheet/rails/action_pack_renderers'
require 'to_spreadsheet/rails/view_helpers'
module ToSpreadsheet
class Railtie < ::Rails::Railtie
initializer "to_spreadsheet.view_helpers" do
config.to_spreadsheet = ActiveSupport::OrderedOptions.new
config.to_spreadsheet.renderer = ToSpreadsheet.renderer

config.after_initialize do |app|
ToSpreadsheet.instance_variable_set("@renderer", app.config.to_spreadsheet.renderer)

require 'to_spreadsheet/rails/action_pack_renderers'
require 'to_spreadsheet/rails/view_helpers'
require 'to_spreadsheet/rails/mime_types'
ActionView::Base.send :include, ToSpreadsheet::Rails::ViewHelpers
end
end
Expand Down

0 comments on commit 263005e

Please sign in to comment.