cloudxls 0.6.2 → 0.7.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/README.md +38 -2
- data/Rakefile +8 -0
- data/cloudxls.gemspec +0 -1
- data/examples/async.rb +24 -0
- data/examples/data.csv +2 -0
- data/examples/files.rb +19 -0
- data/examples/full.rb +42 -0
- data/examples/inline.rb +25 -0
- data/examples/multi_sheet.rb +28 -0
- data/examples/template.xls +0 -0
- data/examples/template.xlsx +0 -0
- data/examples/templates.rb +34 -0
- data/lib/cloudxls.rb +37 -29
- data/lib/cloudxls/version.rb +2 -2
- data/spec/cloudxls_spec.rb +20 -0
- metadata +13 -30
- data/lib/cloudxls/core_ext.rb +0 -122
- data/lib/cloudxls/csv_writer.rb +0 -137
- data/spec/core_ext_spec.rb +0 -58
- data/spec/csv_writer_spec.rb +0 -47
data/README.md
CHANGED
@@ -1,3 +1,39 @@
|
|
1
|
-
#
|
1
|
+
# Installation
|
2
2
|
|
3
|
-
|
3
|
+
gem install cloudxls
|
4
|
+
|
5
|
+
Or in your Gemfile
|
6
|
+
|
7
|
+
gem 'cloudxls', '~> 0.7.0'
|
8
|
+
|
9
|
+
To get started, add the following to your PHP script:
|
10
|
+
|
11
|
+
# Useage
|
12
|
+
|
13
|
+
There are various sample code snippets in the examples folder.
|
14
|
+
|
15
|
+
## Async
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
CloudXLS.api_key = "YOUR-API-KEY"
|
19
|
+
|
20
|
+
response = CloudXLS.async({
|
21
|
+
:data => {
|
22
|
+
:text => "Greeting,Greetee\nHello,World"
|
23
|
+
}
|
24
|
+
})
|
25
|
+
|
26
|
+
redirect_to response.url
|
27
|
+
```
|
28
|
+
|
29
|
+
## Inline
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
CloudXLS.api_key = "YOUR-API-KEY"
|
33
|
+
|
34
|
+
response = CloudXLS.inline(:data => {
|
35
|
+
:text => "Greeting,Greetee\nHello,World"
|
36
|
+
})
|
37
|
+
|
38
|
+
File.open("report.xls", 'wb') {|f| f << response }
|
39
|
+
```
|
data/Rakefile
CHANGED
data/cloudxls.gemspec
CHANGED
data/examples/async.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# ruby examples/async.rb
|
2
|
+
#
|
3
|
+
# Use this in a Rails/Sinatra action to redirect user
|
4
|
+
# directly to the file download (expires after 10min).
|
5
|
+
|
6
|
+
require_relative '../lib/cloudxls'
|
7
|
+
|
8
|
+
unless ENV["CLOUDXLS_API_KEY"]
|
9
|
+
puts "--- WARNING ---"
|
10
|
+
puts "Please add environment variable CLOUDXLS_API_KEY"
|
11
|
+
puts "export CLOUDXLS_API_KEY=YOUR_API_KEY"
|
12
|
+
puts "---------------"
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
|
16
|
+
CloudXLS.api_key = ENV["CLOUDXLS_API_KEY"];
|
17
|
+
|
18
|
+
resp = CloudXLS.async({
|
19
|
+
data: { text: "Greeting,Greetee\nHello,World" },
|
20
|
+
sheet: { name: 'Hello World' },
|
21
|
+
doc: { filename: 'hello-world' }
|
22
|
+
})
|
23
|
+
|
24
|
+
puts "Download file from: #{resp.url}"
|
data/examples/data.csv
ADDED
data/examples/files.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# ruby examples/files.rb
|
2
|
+
|
3
|
+
require_relative '../lib/cloudxls'
|
4
|
+
|
5
|
+
unless ENV["CLOUDXLS_API_KEY"]
|
6
|
+
puts "--- WARNING ---"
|
7
|
+
puts "Please add environment variable CLOUDXLS_API_KEY"
|
8
|
+
puts "export CLOUDXLS_API_KEY=YOUR_API_KEY"
|
9
|
+
puts "---------------"
|
10
|
+
exit
|
11
|
+
end
|
12
|
+
|
13
|
+
CloudXLS.api_key = ENV["CLOUDXLS_API_KEY"];
|
14
|
+
|
15
|
+
resp = CloudXLS.inline({
|
16
|
+
data: { file: File.new("./examples/data.csv") }
|
17
|
+
})
|
18
|
+
|
19
|
+
File.open("out-file.xls", "wb") { |f| f.write resp }
|
data/examples/full.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# ruby examples/full.rb
|
2
|
+
#
|
3
|
+
# With all the options
|
4
|
+
|
5
|
+
require_relative '../lib/cloudxls'
|
6
|
+
|
7
|
+
unless ENV["CLOUDXLS_API_KEY"]
|
8
|
+
puts "--- WARNING ---"
|
9
|
+
puts "Please add environment variable CLOUDXLS_API_KEY"
|
10
|
+
puts "export CLOUDXLS_API_KEY=YOUR_API_KEY"
|
11
|
+
puts "---------------"
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
|
15
|
+
CloudXLS.api_key = ENV["CLOUDXLS_API_KEY"];
|
16
|
+
|
17
|
+
resp = CloudXLS.inline({
|
18
|
+
sheets: {
|
19
|
+
"Sheet1" => {
|
20
|
+
data: {
|
21
|
+
text: "Greeting;Greetee;Date\nHello;World;2011-01-02",
|
22
|
+
separator: ";",
|
23
|
+
date_format: "YYYY-MM-DD", # is default
|
24
|
+
encoding: "UTF-8", # is default
|
25
|
+
},
|
26
|
+
sheet: {
|
27
|
+
cell: "C3", # define cell
|
28
|
+
filters: true, # adds filter boxes
|
29
|
+
auto_size_columns: true, # adjust column width (experimental)
|
30
|
+
cell_formats: "@,@,dd-mmm-yyyy"
|
31
|
+
}
|
32
|
+
},
|
33
|
+
"Sheet3!B2" => {data: {file: File.new("./examples/data.csv") }},
|
34
|
+
},
|
35
|
+
doc: {
|
36
|
+
filename: "output",
|
37
|
+
template: File.new("./examples/template.xls")
|
38
|
+
}
|
39
|
+
})
|
40
|
+
|
41
|
+
File.open("out-full.xls", "wb") { |f| f.write resp }
|
42
|
+
puts "File saved: ./out-full.xls"
|
data/examples/inline.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# ruby examples/inline.rb
|
2
|
+
#
|
3
|
+
# Use to directly download file.
|
4
|
+
|
5
|
+
require_relative '../lib/cloudxls'
|
6
|
+
|
7
|
+
unless ENV["CLOUDXLS_API_KEY"]
|
8
|
+
puts "--- WARNING ---"
|
9
|
+
puts "Please add environment variable CLOUDXLS_API_KEY"
|
10
|
+
puts "export CLOUDXLS_API_KEY=YOUR_API_KEY"
|
11
|
+
puts "---------------"
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
|
15
|
+
CloudXLS.api_key = ENV["CLOUDXLS_API_KEY"];
|
16
|
+
|
17
|
+
resp = CloudXLS.inline({
|
18
|
+
data: { text: "Greeting,Greetee\nHello,World" },
|
19
|
+
sheet: { name: 'Hello World' },
|
20
|
+
doc: { filename: 'hello-world' }
|
21
|
+
})
|
22
|
+
|
23
|
+
|
24
|
+
File.open("out.xls", "wb") { |f| f.write resp }
|
25
|
+
puts "File saved"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# ruby examples/multi_sheet.rb
|
2
|
+
|
3
|
+
require_relative '../lib/cloudxls'
|
4
|
+
|
5
|
+
unless ENV["CLOUDXLS_API_KEY"]
|
6
|
+
puts "--- WARNING ---"
|
7
|
+
puts "Please add environment variable CLOUDXLS_API_KEY"
|
8
|
+
puts "export CLOUDXLS_API_KEY=YOUR_API_KEY"
|
9
|
+
puts "---------------"
|
10
|
+
exit
|
11
|
+
end
|
12
|
+
|
13
|
+
CloudXLS.api_key = ENV["CLOUDXLS_API_KEY"];
|
14
|
+
|
15
|
+
resp = CloudXLS.inline({
|
16
|
+
sheets: {
|
17
|
+
"Sheet1" => {
|
18
|
+
data: {text: "Greeting,Greetee\nHello,World" },
|
19
|
+
sheet: {cell: "C3" }
|
20
|
+
},
|
21
|
+
"Sheet2!D4" => {data: {text: "Greeting,Greetee\nHello,World" }},
|
22
|
+
"Sheet3!B2" => {data: {file: File.new("./examples/data.csv") }},
|
23
|
+
}
|
24
|
+
})
|
25
|
+
|
26
|
+
|
27
|
+
File.open("out-multi_sheet.xls", "wb") { |f| f.write resp }
|
28
|
+
puts "File saved"
|
Binary file
|
Binary file
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# ruby examples/templates.rb
|
2
|
+
#
|
3
|
+
# Merge data into excel files.
|
4
|
+
|
5
|
+
require_relative '../lib/cloudxls'
|
6
|
+
|
7
|
+
unless ENV["CLOUDXLS_API_KEY"]
|
8
|
+
puts "--- WARNING ---"
|
9
|
+
puts "Please add environment variable CLOUDXLS_API_KEY"
|
10
|
+
puts "export CLOUDXLS_API_KEY=YOUR_API_KEY"
|
11
|
+
puts "---------------"
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
|
15
|
+
CloudXLS.api_key = ENV["CLOUDXLS_API_KEY"];
|
16
|
+
|
17
|
+
resp = CloudXLS.inline({
|
18
|
+
data: { text: "Greeting,Greetee\nHello,World" },
|
19
|
+
sheet: { name: 'Hello World' },
|
20
|
+
doc: { template: File.new("./examples/template.xls") }
|
21
|
+
})
|
22
|
+
|
23
|
+
|
24
|
+
File.open("out-template.xls", "wb") { |f| f.write resp }
|
25
|
+
puts "File saved: ./out-template.xls"
|
26
|
+
|
27
|
+
resp = CloudXLS.inline({
|
28
|
+
data: { text: "Greeting,Greetee\nHello,World" },
|
29
|
+
sheet: { name: 'Hello World' },
|
30
|
+
doc: { template: File.new("./examples/template.xlsx") }
|
31
|
+
})
|
32
|
+
|
33
|
+
File.open("out-template.xlsx", "wb") { |f| f.write resp }
|
34
|
+
puts "File saved: ./out-template.xlsx"
|
data/lib/cloudxls.rb
CHANGED
@@ -4,21 +4,17 @@ require 'openssl'
|
|
4
4
|
require 'json'
|
5
5
|
require 'date'
|
6
6
|
require 'rest_client'
|
7
|
-
require '
|
7
|
+
require 'json'
|
8
8
|
|
9
|
-
|
10
|
-
require 'cloudxls/core_ext'
|
11
|
-
require 'cloudxls/csv_writer'
|
9
|
+
require_relative 'cloudxls/version'
|
12
10
|
|
13
|
-
|
11
|
+
class CloudXLS
|
14
12
|
@https = true
|
15
13
|
@api_base = 'api.cloudxls.com'.freeze
|
16
14
|
@api_key = ENV["CLOUDXLS_API_KEY"]
|
17
|
-
# @ssl_bundle_path = File.dirname(__FILE__) + '/data/ca-certificates.crt'
|
18
|
-
@verify_ssl_certs = true
|
19
15
|
|
20
16
|
class << self
|
21
|
-
attr_accessor :api_key, :api_base, :
|
17
|
+
attr_accessor :api_key, :api_base, :api_version, :https
|
22
18
|
end
|
23
19
|
|
24
20
|
def self.api_url(path = '')
|
@@ -26,7 +22,8 @@ module CloudXLS
|
|
26
22
|
"http#{@https ? 's' : ''}://#{@api_key}:@#{@api_base}/v1/#{path}"
|
27
23
|
end
|
28
24
|
|
29
|
-
|
25
|
+
|
26
|
+
class CloudXLSResponse
|
30
27
|
attr_reader :url, :uuid, :response
|
31
28
|
|
32
29
|
def initialize(response)
|
@@ -37,10 +34,32 @@ module CloudXLS
|
|
37
34
|
end
|
38
35
|
end
|
39
36
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
|
38
|
+
def self.async(params = {})
|
39
|
+
if params["mode"]
|
40
|
+
params["mode"] = "async"
|
41
|
+
else
|
42
|
+
params[:mode] = "async"
|
43
|
+
end
|
44
|
+
CloudXLSResponse.new(convert(params))
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def self.inline(params = {})
|
49
|
+
if params["mode"]
|
50
|
+
params["mode"] = "inline"
|
51
|
+
else
|
52
|
+
params[:mode] = "inline"
|
53
|
+
end
|
54
|
+
convert(params)
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# @example
|
59
|
+
# CloudXLS.convert :data => {:file => File.new('/path/to/data.csv', 'r')}
|
60
|
+
# CloudXLS.convert :data => {:file => File.new("foo,bar\nlorem,ipsum") }
|
61
|
+
# CloudXLS.convert :data => {:url => "https://example.com/data.csv"}
|
62
|
+
# CloudXLS.convert :data => {:url => "https://username:password@example.com/data.csv"}
|
44
63
|
#
|
45
64
|
def self.convert(params = {})
|
46
65
|
check_api_key!
|
@@ -48,24 +67,17 @@ module CloudXLS
|
|
48
67
|
headers = {}
|
49
68
|
|
50
69
|
response = execute_request do
|
51
|
-
RestClient.post(api_url("
|
70
|
+
RestClient.post(api_url("convert"), params, headers)
|
52
71
|
end
|
53
72
|
|
54
|
-
|
55
|
-
response
|
56
|
-
else
|
57
|
-
XpipeResponse.new(response)
|
58
|
-
end
|
73
|
+
response
|
59
74
|
end
|
60
75
|
|
76
|
+
# @deprecated
|
61
77
|
def self.xpipe(params = {})
|
62
78
|
convert(params)
|
63
79
|
end
|
64
80
|
|
65
|
-
def validate_params(params)
|
66
|
-
# complain if excel_format together with template
|
67
|
-
end
|
68
|
-
|
69
81
|
def self.execute_request
|
70
82
|
begin
|
71
83
|
return yield
|
@@ -93,8 +105,8 @@ module CloudXLS
|
|
93
105
|
end
|
94
106
|
|
95
107
|
def self.parse_response(response)
|
96
|
-
json =
|
97
|
-
rescue
|
108
|
+
json = JSON.parse(response.body)
|
109
|
+
rescue => e
|
98
110
|
raise general_api_error(response.code, response.body)
|
99
111
|
end
|
100
112
|
|
@@ -111,20 +123,16 @@ private
|
|
111
123
|
when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
|
112
124
|
message = "Could not connect to CloudXLS (#{@api_base}). " +
|
113
125
|
"Please check your internet connection and try again. "
|
114
|
-
|
115
126
|
when RestClient::SSLCertificateNotVerified
|
116
127
|
message = "Could not verify CloudXLS's SSL certificate. " +
|
117
128
|
"Please make sure that your network is not intercepting certificates. "
|
118
|
-
|
119
129
|
when SocketError
|
120
130
|
message = "Unexpected error communicating when trying to connect to CloudXLS. " +
|
121
131
|
"You may be seeing this message because your DNS is not working. " +
|
122
132
|
"To check, try running 'host cloudxls.com' from the command line."
|
123
|
-
|
124
133
|
else
|
125
134
|
message = "Unexpected error communicating with CloudXLS. " +
|
126
135
|
"If this problem persists, let us know at support@cloudxls.com."
|
127
|
-
|
128
136
|
end
|
129
137
|
|
130
138
|
raise StandardError.new(message + "\n\n(Network error: #{e.message})")
|
data/lib/cloudxls/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = '0.
|
1
|
+
class CloudXLS
|
2
|
+
VERSION = '0.7.0'
|
3
3
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "CloudXLS" do
|
4
|
+
before do
|
5
|
+
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "CloudXLS.api_key" do
|
9
|
+
it "should not register api_key" do
|
10
|
+
CloudXLS.api_key = "FOO"
|
11
|
+
expect( CloudXLS.api_key ).to eq("FOO")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should not register api_key" do
|
15
|
+
CloudXLS.api_key = "FOO"
|
16
|
+
CloudXLS.api_key = "BAR"
|
17
|
+
expect( CloudXLS.api_key ).to eq("BAR")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudxls
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-02-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|
@@ -27,28 +27,6 @@ dependencies:
|
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '1.4'
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: multi_json
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: 1.0.4
|
38
|
-
- - <
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '2'
|
41
|
-
type: :runtime
|
42
|
-
prerelease: false
|
43
|
-
version_requirements: !ruby/object:Gem::Requirement
|
44
|
-
none: false
|
45
|
-
requirements:
|
46
|
-
- - ! '>='
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: 1.0.4
|
49
|
-
- - <
|
50
|
-
- !ruby/object:Gem::Version
|
51
|
-
version: '2'
|
52
30
|
- !ruby/object:Gem::Dependency
|
53
31
|
name: minitest
|
54
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,13 +87,19 @@ files:
|
|
109
87
|
- README.md
|
110
88
|
- Rakefile
|
111
89
|
- cloudxls.gemspec
|
90
|
+
- examples/async.rb
|
91
|
+
- examples/data.csv
|
92
|
+
- examples/files.rb
|
93
|
+
- examples/full.rb
|
94
|
+
- examples/inline.rb
|
95
|
+
- examples/multi_sheet.rb
|
96
|
+
- examples/template.xls
|
97
|
+
- examples/template.xlsx
|
98
|
+
- examples/templates.rb
|
112
99
|
- lib/cloudxls.rb
|
113
|
-
- lib/cloudxls/core_ext.rb
|
114
|
-
- lib/cloudxls/csv_writer.rb
|
115
100
|
- lib/cloudxls/version.rb
|
116
101
|
- lib/data/ca-certificates.txt
|
117
|
-
- spec/
|
118
|
-
- spec/csv_writer_spec.rb
|
102
|
+
- spec/cloudxls_spec.rb
|
119
103
|
- spec/spec_helper.rb
|
120
104
|
homepage: https://cloudxls.com
|
121
105
|
licenses: []
|
@@ -142,6 +126,5 @@ signing_key:
|
|
142
126
|
specification_version: 3
|
143
127
|
summary: Ruby wrapper for the CloudXLS xpipe API
|
144
128
|
test_files:
|
145
|
-
- spec/
|
146
|
-
- spec/csv_writer_spec.rb
|
129
|
+
- spec/cloudxls_spec.rb
|
147
130
|
- spec/spec_helper.rb
|
data/lib/cloudxls/core_ext.rb
DELETED
@@ -1,122 +0,0 @@
|
|
1
|
-
# Object#as_csv ensures that object formats are written the same across ruby
|
2
|
-
# versions.
|
3
|
-
#
|
4
|
-
# If an object is known to have issues cross-platform #as_json returns the
|
5
|
-
# desired string.
|
6
|
-
#
|
7
|
-
# Example:
|
8
|
-
#
|
9
|
-
# DateTime.now.as_csv # => "2012-12-24T12:30:01.000+0000"
|
10
|
-
# 5.as_csv # => 5
|
11
|
-
# (0.0/0.0).as_csv # => "#DIV/0!"
|
12
|
-
#
|
13
|
-
|
14
|
-
class Time
|
15
|
-
def as_csv(options = nil)
|
16
|
-
strftime(CloudXLS::DATETIME_FORMAT)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class DateTime
|
21
|
-
def as_csv(options = nil)
|
22
|
-
strftime(CloudXLS::DATETIME_FORMAT)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class String
|
27
|
-
def as_csv(options = nil)
|
28
|
-
self
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class Date
|
33
|
-
def as_csv(options = nil)
|
34
|
-
strftime(CloudXLS::DATE_FORMAT)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
class NilClass
|
39
|
-
def as_csv(options = nil)
|
40
|
-
nil
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class FalseClass
|
45
|
-
def as_csv(options = nil)
|
46
|
-
false
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
class TrueClass
|
51
|
-
def as_csv(options = nil)
|
52
|
-
true
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
class Symbol
|
57
|
-
def as_csv(options = nil)
|
58
|
-
to_s
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
class Numeric
|
63
|
-
def as_csv(options = nil)
|
64
|
-
self
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
class Float
|
69
|
-
# Encoding Infinity or NaN to JSON should return "null". The default returns
|
70
|
-
# "Infinity" or "NaN" which breaks parsing the JSON. E.g. JSON.parse('[NaN]').
|
71
|
-
def as_csv(options = nil) #:nodoc:
|
72
|
-
finite? ? self : "#DIV/0!"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
class Regexp
|
77
|
-
def as_csv(options = nil)
|
78
|
-
to_s
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
module Enumerable
|
83
|
-
def as_csv(options = nil)
|
84
|
-
to_a.as_json(options)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
class Range
|
89
|
-
def as_csv(options = nil)
|
90
|
-
to_s
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
class Hash
|
95
|
-
def as_csv(options = {})
|
96
|
-
attribute_names = keys
|
97
|
-
|
98
|
-
if (only = options[:only])
|
99
|
-
attribute_names = Array(only)
|
100
|
-
elsif (except = options[:except])
|
101
|
-
attribute_names -= Array(except)
|
102
|
-
end
|
103
|
-
|
104
|
-
attribute_names.map do |key|
|
105
|
-
self[key].as_csv
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
class Array
|
111
|
-
def as_csv(options = nil)
|
112
|
-
map do |val|
|
113
|
-
val.as_csv(options)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
class Object
|
119
|
-
def as_csv(options = nil)
|
120
|
-
to_s
|
121
|
-
end
|
122
|
-
end
|
data/lib/cloudxls/csv_writer.rb
DELETED
@@ -1,137 +0,0 @@
|
|
1
|
-
require 'csv'
|
2
|
-
|
3
|
-
module CloudXLS
|
4
|
-
DATETIME_FORMAT = "%FT%T.%L%z".freeze
|
5
|
-
DATE_FORMAT = "%F".freeze
|
6
|
-
|
7
|
-
# Wrapper around stdlib CSV methods.
|
8
|
-
#
|
9
|
-
class CSV
|
10
|
-
def self.generate_line(arr, options = nil)
|
11
|
-
::CSV.generate_line(arr.as_csv, options)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
class CSVWriter
|
17
|
-
# Generates CSV string.
|
18
|
-
#
|
19
|
-
# @param [Enumerable] scope
|
20
|
-
# Method/attribute keys to for the export.
|
21
|
-
#
|
22
|
-
# @option opts [String] :encoding ("UTF-8")
|
23
|
-
# Charset encoding of output.
|
24
|
-
#
|
25
|
-
# @option opts [Boolean] :skip_headers (false)
|
26
|
-
# Do not output headers if first element is an ActiveRecord object.
|
27
|
-
#
|
28
|
-
# @option opts [Array] :only same as #as_json
|
29
|
-
# @option opts [Array] :except same as #as_json
|
30
|
-
# @option opts [Array] :methods same as #as_json
|
31
|
-
#
|
32
|
-
# @return [String]
|
33
|
-
# The full CSV as a string. Titleizes *columns* for the header.
|
34
|
-
#
|
35
|
-
def self.text(scope, opts = {})
|
36
|
-
encoding = opts.delete(:encoding) || "UTF-8"
|
37
|
-
skip_headers = opts.delete(:skip_headers) || false
|
38
|
-
|
39
|
-
str = ::CSV.generate(:encoding => encoding) do |csv|
|
40
|
-
|
41
|
-
enum_method = scope_enumerator(scope)
|
42
|
-
scope.send(enum_method) do |record|
|
43
|
-
|
44
|
-
if skip_headers == false && !record.is_a?(Array)
|
45
|
-
titles = CloudXLS::Util.titles_for_serialize_options(record, opts)
|
46
|
-
csv << titles.map(&:titleize)
|
47
|
-
skip_headers = true
|
48
|
-
end
|
49
|
-
|
50
|
-
csv << record.as_csv(opts)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
str.strip!
|
54
|
-
str
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
# Generates Enumerator for streaming response.
|
59
|
-
#
|
60
|
-
# Example
|
61
|
-
#
|
62
|
-
# def index
|
63
|
-
# # setup headers...
|
64
|
-
# stream = CloudXLS::CSVWriter.csv_enumerator(Post.all, only: [:title, :author])
|
65
|
-
# self.response_body = stream
|
66
|
-
# end
|
67
|
-
#
|
68
|
-
# Same options and parameters as #text.
|
69
|
-
#
|
70
|
-
# @return [Enumerator] enumerator to use for streaming response.
|
71
|
-
#
|
72
|
-
def self.enumerator(scope, options = {})
|
73
|
-
encoding = options.delete(:encoding) || "UTF-8"
|
74
|
-
skip_headers = options.delete(:skip_headers) || false
|
75
|
-
|
76
|
-
Enumerator.new do |stream|
|
77
|
-
enum_method = scope_enumerator(scope)
|
78
|
-
|
79
|
-
scope.send(enum_method) do |record|
|
80
|
-
if !skip_headers && !record.is_a?(Array)
|
81
|
-
titles = CloudXLS::Util.titles_for_serialize_options(record, options)
|
82
|
-
stream << titles.map(&:titleize).to_csv
|
83
|
-
skip_headers = true
|
84
|
-
end
|
85
|
-
|
86
|
-
stream << record.as_csv(options).to_csv
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
|
92
|
-
def self.scope_enumerator(scope)
|
93
|
-
if scope.respond_to?(:arel) &&
|
94
|
-
scope.arel.orders.blank? &&
|
95
|
-
scope.arel.taken.blank?
|
96
|
-
:find_each
|
97
|
-
else
|
98
|
-
:each
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
module CloudXLS
|
105
|
-
class Util
|
106
|
-
# Column and method-names of a model that correspond to the values from
|
107
|
-
# a #as_json/#as_csv call. In the same order.
|
108
|
-
#
|
109
|
-
# Example
|
110
|
-
#
|
111
|
-
# CloudXLS::Util.titles_for_serialize_options(Post.new, only: [:author, :title], method: [:slug])
|
112
|
-
# # => ['title', 'author', 'slug']
|
113
|
-
#
|
114
|
-
def self.titles_for_serialize_options(record, options = {})
|
115
|
-
attribute_names = record.attributes.keys
|
116
|
-
if only = options[:only]
|
117
|
-
arr = []
|
118
|
-
Array(only).map(&:to_s).each do |key|
|
119
|
-
arr.push(key) if attribute_names.include?(key)
|
120
|
-
end
|
121
|
-
attribute_names = arr
|
122
|
-
elsif except = options[:except]
|
123
|
-
attribute_names -= Array(except).map(&:to_s)
|
124
|
-
end
|
125
|
-
|
126
|
-
Array(options[:methods]).each do |m|
|
127
|
-
m = m.to_s
|
128
|
-
if record.respond_to?(m)
|
129
|
-
unless attribute_names.include?(m)
|
130
|
-
attribute_names.push(val)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
attribute_names
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
data/spec/core_ext_spec.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "as_csv" do
|
4
|
-
it "should handle Hash" do
|
5
|
-
expect( {:foo => 1, :bar => Date.new(2013,12,24)}.as_csv ).to eq([1,'2013-12-24'])
|
6
|
-
end
|
7
|
-
|
8
|
-
it "should handle Hash with :only" do
|
9
|
-
hash = {:foo => "foo", :bar => "bar"}
|
10
|
-
expect( hash.as_csv(:only => :foo) ).to eq(["foo"])
|
11
|
-
expect( hash.as_csv(:only => [:foo]) ).to eq(["foo"])
|
12
|
-
expect( hash.as_csv(:only => [:bar]) ).to eq(["bar"])
|
13
|
-
expect( hash.as_csv(:only => [:foo, :bar]) ).to eq(["foo", "bar"])
|
14
|
-
expect( hash.as_csv(:only => [:bar, :foo]) ).to eq(["bar", "foo"])
|
15
|
-
#expect( hash.as_csv(:only => [:bar, :baz, :foo]) ).to eq(["foo", nil, "bar"])
|
16
|
-
end
|
17
|
-
|
18
|
-
it "should handle Array" do
|
19
|
-
expect( [1, Date.new(2013,12,24)].as_csv ).to eq([1,'2013-12-24'])
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should handle Symbol" do
|
23
|
-
expect( :foo.as_csv ).to eq('foo')
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should handle Symbol" do
|
27
|
-
expect( :foo.as_csv ).to eq('foo')
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should handle nil" do
|
31
|
-
expect( nil.as_csv ).to eq(nil)
|
32
|
-
end
|
33
|
-
|
34
|
-
it "should handle boolean" do
|
35
|
-
expect( false.as_csv ).to eq(false)
|
36
|
-
expect( true.as_csv ).to eq(true)
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should handle float" do
|
40
|
-
expect( (1.123).as_csv ).to eq(1.123)
|
41
|
-
expect( (1.0/0.0).as_csv ).to eq("#DIV/0!")
|
42
|
-
expect( (-1.0/0.0).as_csv ).to eq("#DIV/0!")
|
43
|
-
expect( (0.0/0.0).as_csv ).to eq("#DIV/0!")
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should handle Time" do
|
47
|
-
expect( Time.new(2012,12,24,18,30,5,'+00:00').as_csv ).to eq("2012-12-24T18:30:05.000+0000")
|
48
|
-
end
|
49
|
-
|
50
|
-
it "should handle DateTime" do
|
51
|
-
expect( DateTime.new(2012,12,24,18,30,5,'+00:00').as_csv ).to eq("2012-12-24T18:30:05.000+0000")
|
52
|
-
expect( DateTime.new(2012,12,24).as_csv ).to eq("2012-12-24T00:00:00.000+0000")
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should handle DateTime" do
|
56
|
-
expect( Date.new(2012,12,24).as_csv ).to eq("2012-12-24")
|
57
|
-
end
|
58
|
-
end
|
data/spec/csv_writer_spec.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "CloudXLS::CSVWriter" do
|
4
|
-
before do
|
5
|
-
@writer = CloudXLS::CSVWriter
|
6
|
-
end
|
7
|
-
|
8
|
-
describe "with array" do
|
9
|
-
it "should not titleize" do
|
10
|
-
expect( @writer.text([['foo','bar'],[1,2]]) ).to eq("foo,bar\n1,2")
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should escape titles" do
|
14
|
-
expect( @writer.text([['bar"baz']]) ).to eq("\"bar\"\"baz\"")
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should escape rows" do
|
18
|
-
expect( @writer.text([['title'],['bar"baz']]) ).to eq("title\n\"bar\"\"baz\"")
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should write YYYY-MM-DD for Date" do
|
22
|
-
expect( @writer.text([[Date.new(2012,12,24)]]) ).to eq("2012-12-24")
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should write xmlschema for DateTime" do
|
26
|
-
# TODO: make UTC consistent
|
27
|
-
expect( @writer.text([[DateTime.new(2012,12,24,18,30,5,'+0000')]]) ).to eq("2012-12-24T18:30:05.000+0000")
|
28
|
-
expect( @writer.text([[DateTime.new(2012,12,24,18,30,5,'+0000').to_time.utc]]) ).to eq("2012-12-24T18:30:05.000+0000")
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should write nothing for nil" do
|
32
|
-
expect( @writer.text([[nil,nil]]) ).to eq(",")
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should write \"\" for empty string" do
|
36
|
-
expect( @writer.text([["",""]]) ).to eq('"",""')
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should write integers" do
|
40
|
-
expect( @writer.text([[-1,0,1,1_000_000]]) ).to eq('-1,0,1,1000000')
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should write floats" do
|
44
|
-
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')
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|