cloudxls-rails 0.4.3 → 0.5.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/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
|