cloudxls-rails 0.4.3 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/cloudxls-rails.gemspec +1 -1
- data/lib/cloudxls-rails/activemodel.rb +88 -0
- data/lib/cloudxls-rails/activesupport.rb +9 -0
- data/lib/cloudxls-rails/handlers/csv.rb +1 -2
- data/lib/cloudxls-rails/handlers/xls.rb +1 -2
- data/lib/cloudxls-rails/handlers/xlsx.rb +1 -2
- data/lib/cloudxls-rails/version.rb +1 -1
- data/lib/cloudxls-rails.rb +2 -0
- data/spec/csv_writer_spec.rb +54 -8
- data/spec/integration_spec.rb +15 -0
- data/spec/test_app/app/controllers/posts_controller.rb +7 -3
- data/spec/test_app/config/routes.rb +1 -0
- metadata +5 -3
data/cloudxls-rails.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = CloudXLSRails::VERSION
|
17
17
|
|
18
|
-
gem.add_dependency('cloudxls', '~> 0.
|
18
|
+
gem.add_dependency('cloudxls', '~> 0.5.0')
|
19
19
|
|
20
20
|
gem.add_development_dependency "rake"
|
21
21
|
gem.add_development_dependency "webmock"
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'active_model/serialization'
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module Serializers
|
5
|
+
module CSV
|
6
|
+
include ActiveModel::Serialization
|
7
|
+
|
8
|
+
# Returns an array representing the model. Some configuration can be
|
9
|
+
# passed through +options+.
|
10
|
+
#
|
11
|
+
# Without any +options+, the returned Array will include all the model's
|
12
|
+
# attributes.
|
13
|
+
#
|
14
|
+
# user = User.find(1)
|
15
|
+
# user.as_csv
|
16
|
+
# # => [1, "Konata Izumi", 16, "2006-08-01", true]
|
17
|
+
#
|
18
|
+
# The :only and :except options can be used to limit
|
19
|
+
# the attributes included, and work similar to the +attributes+ method.
|
20
|
+
#
|
21
|
+
# user.as_csv(only: [:id, :name])
|
22
|
+
# # => [1, "Konata Izumi"]
|
23
|
+
#
|
24
|
+
# user.as_csv(except: [:id, :created_at, :age])
|
25
|
+
# # => ["Konata Izumi", true]
|
26
|
+
#
|
27
|
+
# To include the result of some method calls on the model use :methods:
|
28
|
+
#
|
29
|
+
# user.as_csv(methods: :permalink)
|
30
|
+
# # => [1, "Konata Izumi", 16, "2006-08-01", true, "1-konata-izumi"]
|
31
|
+
#
|
32
|
+
def as_csv(options = nil)
|
33
|
+
options ||= {}
|
34
|
+
|
35
|
+
attribute_names = attributes.keys
|
36
|
+
if only = options[:only]
|
37
|
+
attribute_names = Array(only).map(&:to_s).select do |key|
|
38
|
+
attribute_names.include?(key)
|
39
|
+
end
|
40
|
+
elsif except = options[:except]
|
41
|
+
attribute_names -= Array(except).map(&:to_s)
|
42
|
+
end
|
43
|
+
|
44
|
+
arr = []
|
45
|
+
attribute_names.each do |n|
|
46
|
+
arr.push(read_attribute_for_serialization(n).as_csv)
|
47
|
+
end
|
48
|
+
|
49
|
+
Array(options[:methods]).each do |m|
|
50
|
+
if respond_to?(m)
|
51
|
+
val = send(m)
|
52
|
+
if idx = attribute_names.index(m.to_s)
|
53
|
+
arr[idx] = val
|
54
|
+
else
|
55
|
+
arr.push(val)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
arr
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# Hook method defining how an attribute value should be retrieved for
|
66
|
+
# serialization. By default this is assumed to be an instance named after
|
67
|
+
# the attribute. Override this method in subclasses should you need to
|
68
|
+
# retrieve the value for a given attribute differently:
|
69
|
+
#
|
70
|
+
# class MyClass
|
71
|
+
# include ActiveModel::Validations
|
72
|
+
#
|
73
|
+
# def initialize(data = {})
|
74
|
+
# @data = data
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# def read_attribute_for_serialization(key)
|
78
|
+
# @data[key]
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
alias :read_attribute_for_serialization :send
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
ActiveRecord::Base.send(:include, ActiveModel::Serializers::CSV)
|
88
|
+
|
@@ -33,12 +33,11 @@ end
|
|
33
33
|
|
34
34
|
ActionController::Renderers.add :csv do |scope, options|
|
35
35
|
filename = options.fetch(:filename, "data-#{DateTime.now.to_s}.csv")
|
36
|
-
columns = options[:columns]
|
37
36
|
|
38
37
|
if options[:stream]
|
39
38
|
CloudXLSRails::CSVResponder.stream!(self, scope, options)
|
40
39
|
else # no stream:
|
41
|
-
data = CloudXLS::CSVWriter.text(scope,
|
40
|
+
data = CloudXLS::CSVWriter.text(scope, options)
|
42
41
|
|
43
42
|
send_data data,
|
44
43
|
type: Mime::CSV,
|
@@ -6,13 +6,12 @@ end
|
|
6
6
|
module CloudXLSRails
|
7
7
|
class XLSResponder
|
8
8
|
def self.redirect!(controller, scope, options)
|
9
|
-
columns = options.fetch(:columns, nil)
|
10
9
|
xdata = options[:data] || {}
|
11
10
|
unless (xdata.has_key?(:text) ||
|
12
11
|
xdata.has_key?(:url ) ||
|
13
12
|
xdata.has_key?(:file) )
|
14
13
|
|
15
|
-
xdata[:text] = CloudXLS::CSVWriter.text(scope,
|
14
|
+
xdata[:text] = CloudXLS::CSVWriter.text(scope, options)
|
16
15
|
end
|
17
16
|
|
18
17
|
xopts = {:data => xdata}
|
@@ -6,13 +6,12 @@ end
|
|
6
6
|
module CloudXLSRails
|
7
7
|
class XLSXResponder
|
8
8
|
def self.redirect!(controller, scope, options)
|
9
|
-
columns = options.fetch(:columns, nil)
|
10
9
|
xdata = options[:data] || {}
|
11
10
|
unless (xdata.has_key?(:text) ||
|
12
11
|
xdata.has_key?(:url ) ||
|
13
12
|
xdata.has_key?(:file) )
|
14
13
|
|
15
|
-
xdata[:text] = CloudXLS::CSVWriter.text(scope,
|
14
|
+
xdata[:text] = CloudXLS::CSVWriter.text(scope, options)
|
16
15
|
end
|
17
16
|
|
18
17
|
xopts = {:data => xdata}
|
data/lib/cloudxls-rails.rb
CHANGED
@@ -2,6 +2,8 @@ require 'cloudxls' # cloudxls gem
|
|
2
2
|
|
3
3
|
require 'action_controller'
|
4
4
|
require 'cloudxls-rails/version'
|
5
|
+
require 'cloudxls-rails/activesupport'
|
6
|
+
require 'cloudxls-rails/activemodel'
|
5
7
|
require 'cloudxls-rails/handlers/csv'
|
6
8
|
require 'cloudxls-rails/handlers/xls'
|
7
9
|
require 'cloudxls-rails/handlers/xlsx'
|
data/spec/csv_writer_spec.rb
CHANGED
@@ -1,12 +1,58 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
describe CloudXLS::Util do
|
4
|
+
describe "titles_for_serialize_options" do
|
5
|
+
it "should work with a Post.all" do
|
6
|
+
expect( CloudXLS::Util.titles_for_serialize_options(Post.new, :only => "title") ).to eq(["title"])
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
3
11
|
describe "CloudXLS::CSVWriter" do
|
4
12
|
before do
|
5
13
|
@writer = CloudXLS::CSVWriter
|
6
14
|
end
|
7
15
|
|
8
16
|
describe "with array" do
|
9
|
-
|
17
|
+
it "should not titleize" do
|
18
|
+
expect( @writer.text([['foo','bar'],[1,2]]) ).to eq("foo,bar\n1,2")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should escape titles" do
|
22
|
+
expect( @writer.text([['bar"baz']]) ).to eq("\"bar\"\"baz\"")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should escape rows" do
|
26
|
+
expect( @writer.text([['title'],['bar"baz']]) ).to eq("title\n\"bar\"\"baz\"")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should write YYYY-MM-DD for Date" do
|
30
|
+
expect( @writer.text([[Date.new(2012,12,24)]]) ).to eq("2012-12-24")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should write xmlschema for DateTime" do
|
34
|
+
# TODO: make UTC consistent
|
35
|
+
expect( DateTime.new(2012,12,24,18,30,5,'+0000').as_csv ).to eq("2012-12-24T18:30:05.000+0000")
|
36
|
+
expect( [DateTime.new(2012,12,24,18,30,5,'+0000')].as_csv ).to eq(["2012-12-24T18:30:05.000+0000"])
|
37
|
+
expect( @writer.text([[DateTime.new(2012,12,24,18,30,5,'+0000')]]) ).to eq("2012-12-24T18:30:05.000+0000")
|
38
|
+
expect( @writer.text([[DateTime.new(2012,12,24,18,30,5,'+0000').to_time.utc]]) ).to eq("2012-12-24T18:30:05.000+0000")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should write nothing for nil" do
|
42
|
+
expect( @writer.text([[nil,nil]]) ).to eq(",")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should write \"\" for empty string" do
|
46
|
+
expect( @writer.text([["",""]]) ).to eq('"",""')
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should write integers" do
|
50
|
+
expect( @writer.text([[-1,0,1,1_000_000]]) ).to eq('-1,0,1,1000000')
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should write floats" do
|
54
|
+
expect( @writer.text([[-1.0,0.0,1.0,1_000_000.0,1.234567]]) ).to eq('-1.0,0.0,1.0,1000000.0,1.234567')
|
55
|
+
end
|
10
56
|
end
|
11
57
|
|
12
58
|
describe "#text with AR" do
|
@@ -22,29 +68,29 @@ describe "CloudXLS::CSVWriter" do
|
|
22
68
|
:published => false)
|
23
69
|
end
|
24
70
|
|
25
|
-
it "given no records
|
71
|
+
it "given no records returns empty string" do
|
26
72
|
Post.delete_all
|
27
|
-
expect( @writer.text(Post.all, :
|
73
|
+
expect( @writer.text(Post.all, :only => [:title, :visits]) ).to eq("")
|
28
74
|
end
|
29
75
|
|
30
76
|
it "should work with a Post.all" do
|
31
|
-
expect( @writer.text(Post.all, :
|
77
|
+
expect( @writer.text(Post.all, :only => [:title, :visits]) ).to eq("Title,Visits\nhello world,12032")
|
32
78
|
end
|
33
79
|
|
34
80
|
it "should work with a Post.limit" do
|
35
|
-
expect( @writer.text(Post.limit(10), :
|
81
|
+
expect( @writer.text(Post.limit(10), :only => [:title, :visits]) ).to eq("Title,Visits\nhello world,12032")
|
36
82
|
end
|
37
83
|
|
38
84
|
it "should work with a Post.all.to_a" do
|
39
|
-
expect( @writer.text(Post.all.to_a, :
|
85
|
+
expect( @writer.text(Post.all.to_a, :only => [:title, :visits]) ).to eq("Title,Visits\nhello world,12032")
|
40
86
|
end
|
41
87
|
|
42
88
|
it "should write xmlschema for DateTime" do
|
43
|
-
expect( @writer.text(Post.all, :
|
89
|
+
expect( @writer.text(Post.all, :only => [:expired_at]) ).to eq("Expired At\n2013-12-25T12:30:30.000+0000")
|
44
90
|
end
|
45
91
|
|
46
92
|
it "should write YYYY-MM-DD for Date" do
|
47
|
-
expect( @writer.text(Post.all, :
|
93
|
+
expect( @writer.text(Post.all, :only => [:published_on]) ).to eq("Published On\n2013-12-24")
|
48
94
|
end
|
49
95
|
end
|
50
96
|
end
|
data/spec/integration_spec.rb
CHANGED
@@ -14,6 +14,13 @@ describe 'Request', :type => :request do
|
|
14
14
|
:published => false)
|
15
15
|
end
|
16
16
|
|
17
|
+
it "#as_csv" do
|
18
|
+
expect( @post.as_csv(except: [:unix_timestamp, :created_at, :updated_at]) ).to eq([@post.id, "hello world", 12_032, 0.24, "2013-12-24", "2013-12-25T12:30:30.000+0000", false])
|
19
|
+
expect( @post.as_csv(only: [:title]) ).to eq(["hello world"])
|
20
|
+
expect( @post.as_csv(only: [:title, :visits]) ).to eq(["hello world", 12_032])
|
21
|
+
expect( @post.as_csv(only: [:expired_at]) ).to eq(["2013-12-25T12:30:30.000+0000"])
|
22
|
+
end
|
23
|
+
|
17
24
|
it "has a working test_app" do
|
18
25
|
visit '/'
|
19
26
|
page.should have_content "Users"
|
@@ -27,6 +34,14 @@ describe 'Request', :type => :request do
|
|
27
34
|
].join("\n")
|
28
35
|
end
|
29
36
|
|
37
|
+
it "/posts/all_columns.csv streams csv" do
|
38
|
+
visit '/posts/all_columns.csv'
|
39
|
+
page.should have_content [
|
40
|
+
"Id,Title,Visits,Conversion Rate,Published On,Expired At,Published,Unix Timestamp,Created At,Updated At",
|
41
|
+
"1,hello world,12032,0.24,2013-12-24,2013-12-25T12:30:30.000+0000,false,2013-12-25T12:30:30.000+0000,#{@post.created_at.as_csv},#{@post.updated_at.as_csv}"
|
42
|
+
].join("\n")
|
43
|
+
end
|
44
|
+
|
30
45
|
it "/posts/stream.csv streams csv" do
|
31
46
|
visit '/posts/stream.csv'
|
32
47
|
page.should have_content [
|
@@ -3,19 +3,23 @@ class PostsController < ApplicationController
|
|
3
3
|
|
4
4
|
def index
|
5
5
|
respond_with(Post.all,
|
6
|
-
:
|
6
|
+
:only => export_attributes)
|
7
|
+
end
|
8
|
+
|
9
|
+
def all_columns
|
10
|
+
respond_with(Post.all.to_a)
|
7
11
|
end
|
8
12
|
|
9
13
|
def stream
|
10
14
|
respond_with(Post.all,
|
11
15
|
:stream => true,
|
12
|
-
:
|
16
|
+
:only => export_attributes)
|
13
17
|
end
|
14
18
|
|
15
19
|
def stream_with_custom_url
|
16
20
|
respond_with(Post.all,
|
17
21
|
:stream => "/successful_redirect",
|
18
|
-
:
|
22
|
+
:only => export_attributes)
|
19
23
|
end
|
20
24
|
|
21
25
|
# Used for stub/mocking a redirect request
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudxls-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.
|
21
|
+
version: 0.5.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.
|
29
|
+
version: 0.5.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: rake
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,6 +120,8 @@ files:
|
|
120
120
|
- Rakefile
|
121
121
|
- cloudxls-rails.gemspec
|
122
122
|
- lib/cloudxls-rails.rb
|
123
|
+
- lib/cloudxls-rails/activemodel.rb
|
124
|
+
- lib/cloudxls-rails/activesupport.rb
|
123
125
|
- lib/cloudxls-rails/handlers/csv.rb
|
124
126
|
- lib/cloudxls-rails/handlers/xls.rb
|
125
127
|
- lib/cloudxls-rails/handlers/xlsx.rb
|