zuora_apiD 1.6.08
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.gitlab-ci.yml +50 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/README.md +147 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/insights_api/login.rb +221 -0
- data/lib/zuora_apiD.rb +9 -0
- data/lib/zuora_apiD/exceptions.rb +106 -0
- data/lib/zuora_apiD/login.rb +808 -0
- data/lib/zuora_apiD/logins/basic.rb +103 -0
- data/lib/zuora_apiD/logins/oauth.rb +106 -0
- data/lib/zuora_apiD/version.rb +3 -0
- data/zuora_apiD.gemspec +30 -0
- metadata +193 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b454b505a098914ff5a66e5a179ae58e7a9ff339898d4b6603482fe25597bed3
|
4
|
+
data.tar.gz: bc3aeb980a06cf2e9ea7cdb625053b68c5283ccf2f8903a76e22c1f99bd71696
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fc94d85ece22c49d42de5d934202cb2c415a0f45457a9d67adb101980f9d4334e5be59fe14a11ad25db0aab3acd37e2c5156bc23c47d7307687ba168d813301f
|
7
|
+
data.tar.gz: bea20a84aa2662980613406cd4fef85bee37fb7a77448bd504857d657903996b0db9de841e00635c0b956e7f28116b7326c37449e39a5429cdcccdc97c4c27c5
|
data/.gitignore
ADDED
data/.gitlab-ci.yml
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
image: ruby:2.3.1
|
3
|
+
stages:
|
4
|
+
- setup
|
5
|
+
- test
|
6
|
+
- deploy
|
7
|
+
|
8
|
+
setup:
|
9
|
+
stage: setup
|
10
|
+
allow_failure: true
|
11
|
+
cache:
|
12
|
+
key: gems
|
13
|
+
paths:
|
14
|
+
- vendor/bundle
|
15
|
+
script:
|
16
|
+
- apt-get update -qy
|
17
|
+
- apt-get install -y nodejs
|
18
|
+
- bundle install
|
19
|
+
|
20
|
+
rubocop-testing:
|
21
|
+
stage: test
|
22
|
+
allow_failure: true
|
23
|
+
script:
|
24
|
+
- gem install rubocop
|
25
|
+
- rubocop --lint
|
26
|
+
|
27
|
+
security-testing:
|
28
|
+
stage: test
|
29
|
+
allow_failure: true
|
30
|
+
script:
|
31
|
+
- gem install brakeman
|
32
|
+
- brakeman
|
33
|
+
|
34
|
+
rspec-testing:
|
35
|
+
stage: test
|
36
|
+
script:
|
37
|
+
- bundle install
|
38
|
+
- rspec
|
39
|
+
|
40
|
+
rubygems-deploy:
|
41
|
+
stage: deploy
|
42
|
+
allow_failure: false
|
43
|
+
script:
|
44
|
+
- bundle install
|
45
|
+
- gem install rake
|
46
|
+
- version=$(rake install | grep -o 'pkg/zuora_api-.*gem')
|
47
|
+
- curl -u $USERNAME:$PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
|
48
|
+
- gem push $version
|
49
|
+
only:
|
50
|
+
- master
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
# Zuora Gem
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/zuora_api.svg)](https://badge.fury.io/rb/zuora_api) [![coverage report](https://gitlab.zuora.com/Connect/zuora-gem/badges/master/coverage.svg)](https://gitlab.zuora.com/Connect/zuora-gem/commits/master)
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
Add this line to your application's Gemfile:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
gem 'zuora_apiD'
|
10
|
+
```
|
11
|
+
Then execute `bundle install` in your terminal
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
### Zuora Login Object
|
16
|
+
In order to make API calls a Zuora Login object must be created
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
zuora_client = ZuoraAPI::Login.new(username: "username", password: "password", url: "url")
|
20
|
+
```
|
21
|
+
|
22
|
+
| Name | Type | Description | Example |
|
23
|
+
| ------------------- | ----------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
24
|
+
| username | `Attribute` | Username to the Zuora environment | `zuora_client.username = "username"` |
|
25
|
+
| password | `Attribute` | password to the Zuora environment | `zuora_client.password = "Password"` |
|
26
|
+
| url | `Attribute` | Endpoint to the Zuora tenant | `zuora_client.url = "www.zuora.com"` |
|
27
|
+
| wsdl_number | `Attribute` | WSDL number of the zuora login | `wsdl = zuora_client.wsdl_number` |
|
28
|
+
| status | `Attribute` | Status of the login | `zuora_client.status` |
|
29
|
+
| current_session | `Attribute` | Current session for the login | `zuora_client.current_session` |
|
30
|
+
| environment | `Attribute` | environment of the login | `zuora_client.environment` |
|
31
|
+
| errors | `Attribute` | Any errors that the login has based on the login call | `zuora_client.errors` |
|
32
|
+
| current_error | `Attribute` | Current error from the new_session call | `zuora_client.current_error` |
|
33
|
+
| user_info | `Attribute` | Information related to the login | `zuora_client.user_info` |
|
34
|
+
| tenant_id | `Attribute` | Tenant ID the login is associated to | `zuora_client.tenant_id` |
|
35
|
+
| tenant_name | `Attribute` | Tenant Name of tenant the login is associated to | `zuora_client.tenant_name` |
|
36
|
+
| entity_id | `Attribute` | Current entity the login session is associated to | `zuora_client.entity_id` |
|
37
|
+
| rest_call | `Method` | Executes a REST call | `zuora_client.rest_call()` |
|
38
|
+
| soap_call | `Method` | Executes a SOAP call | `output_xml, input_xml = zuora_client.soap_call() do `|xml, args|` xml['ns1'].query do xml['ns1'].queryString "select id, name from account" end end` |
|
39
|
+
| query | `Method` | Executes a query call | `zuora_client.query("select id, name from account")` |
|
40
|
+
| getDataSourceExport | `Method` | Pulls a data source export with the given query and returns the file location | `zuora_client.getDataSourceExport("select id, name from account")` |
|
41
|
+
| describe_call | `Method` | Performs the describe call against the Zuora tenant for all objects or a specific object | `response = zuora_client.describe_call("Account")` |
|
42
|
+
| createJournalRun | `Method` | Creates a Journal Run | `zuora_client.createJournalRun(call)` |
|
43
|
+
| checkJRStatus | `Method` | Checks the status of a journal run | `zuora_client.checkJRStatus(journal_run_id)` |
|
44
|
+
| update_environment | `Method` | Sets the login's environment based on the url | `zuora_client.update_environment` |
|
45
|
+
| aqua_endpoint | `Method` | Returns the AQuA endpoint for the login based off the environment | `zuora_client.aqua_endpoint` |
|
46
|
+
| rest_endpoint | `Method` | Returns the REST endpoint for the login based off the environment | `zuora_client.rest_endpoint` |
|
47
|
+
| fileURL | `Method` | Returns the URL for files | `zuora_client.fileURL` |
|
48
|
+
| dateFormat | `Method` | Returns the data format syntax based on the wsdl_number | `zuora_client.dateFormat` |
|
49
|
+
| new_session | `Method` | Create a new session | `zuora_client.new_session` |
|
50
|
+
| get_session | `Method` | Returns the current session | `zuora_client.get_session`|
|
51
|
+
|
52
|
+
## Rest Call
|
53
|
+
```ruby
|
54
|
+
zuora_client.rest_call(method: :get, body: {}, url: zuora_client.rest_endpoint("catalog/products?pageSize=4"))
|
55
|
+
```
|
56
|
+
|
57
|
+
### Soap Call
|
58
|
+
Returns both output and input XML
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
zuora_client.soap_call(ns1: 'ns1', ns2: 'ns2', batch_size: nil, single_transaction: false)
|
62
|
+
```
|
63
|
+
|
64
|
+
Example Call
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
output_xml, input_xml = zuora_client.soap_call() do |xml, args|
|
68
|
+
xml['ns1'].query do
|
69
|
+
xml['ns1'].queryString "select id, name from account"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
```
|
73
|
+
### Query
|
74
|
+
```ruby
|
75
|
+
zuora_client.query("select id from account")
|
76
|
+
```
|
77
|
+
### Data Export
|
78
|
+
Returns the file location of the data source export after downloading from Zuora
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
zuora_client.getDataSourceExport("select id from account")
|
82
|
+
```
|
83
|
+
|
84
|
+
| Name | Description | Default | Example |
|
85
|
+
| --------- | ---------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------- |
|
86
|
+
| query | The query to execute | `N/A` | `zuora_client.getDataSourceExport("select id from account")` |
|
87
|
+
| zip | Indicates if the data source export should be a zip | `true` | `zuora_client.getDataSourceExport("select id from account", zip: false)` |
|
88
|
+
| extract | Indicates if the data source export should be extracted if it is a zip | `true` | `zuora_client.getDataSourceExport("select id from account", extract: false)` |
|
89
|
+
| encrypted | Indicates if the data source export should be encrypted | `false` | `zuora_client.getDataSourceExport("select id from account", encrypted: true)` |
|
90
|
+
|
91
|
+
### Describe Call
|
92
|
+
This returns all available objects from the describe call as a hash. This response can be accessed by using response["Account"] to retrieve all related data about that object.
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
response = zuora_client.describe_call("Account")
|
96
|
+
```
|
97
|
+
This returns all information and fields related to that object model as a hash.
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
response = zuora_client.describe_call()
|
101
|
+
```
|
102
|
+
|
103
|
+
### Journal Run
|
104
|
+
```ruby
|
105
|
+
zuora_client.createJournalRun(call)
|
106
|
+
```
|
107
|
+
|
108
|
+
## Insights API
|
109
|
+
|
110
|
+
In order to make API calls a Zuora Login object must be created by running:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
insightsapi = InsightsAPI::Login.new(api_token: "api token", url: "Nw1.api.insights.zuora.com/api/")
|
114
|
+
```
|
115
|
+
|
116
|
+
Note that the login will default to the insights production url.
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
Date format: "YYYY-MM-DDT00:00:00Z"
|
120
|
+
```
|
121
|
+
|
122
|
+
### Uploading Data into Insights
|
123
|
+
```ruby
|
124
|
+
insightsapi.upload_into_insights(dataSourceName, recordType, batchDate, filePath)
|
125
|
+
```
|
126
|
+
dataSourceName: What system the data is coming from.
|
127
|
+
recordType: The type of records ie: "EVENTS, ATTRIBUTES, and METRICS"
|
128
|
+
batachDate: The date the data applies to.
|
129
|
+
|
130
|
+
### Describing Insights Data
|
131
|
+
```ruby
|
132
|
+
insightsapi.describe(type: "ACCOUNT/USER", object: "ATTRIBUTES/EVENTS/SEGMENTS/METRICS")
|
133
|
+
```
|
134
|
+
Returns json payload describing attributes, events, metrics for each Account or User.
|
135
|
+
|
136
|
+
### Downloading Data from Insights
|
137
|
+
```ruby
|
138
|
+
insightsapi.data_export_insights(objecttype, segmentuuid, startDate: nil, endDate: nil, tries: 30)
|
139
|
+
```
|
140
|
+
```ruby
|
141
|
+
insightsapi.data_export_insights_file(objecttype, segmentuuid, startDate: nil, endDate: nil, tries: 30)
|
142
|
+
```
|
143
|
+
Both do the same thing except one returns a url(data_export_insights) to download the file yourself and the other returns an actual Ruby temporary file(data_export_insights_file).
|
144
|
+
|
145
|
+
objectype: "ACCOUNT/USER"
|
146
|
+
|
147
|
+
segmentuuid: A single or array of string or int of a segment uuid(s) that you get from the describe call. The csv holds a column with a bool that represents if that User or Account belongs to that segment.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "zuora"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
require "httparty"
|
2
|
+
module InsightsAPI
|
3
|
+
class Login
|
4
|
+
attr_accessor :api_token, :url
|
5
|
+
|
6
|
+
def initialize(api_token: nil, url: nil, **keyword_args)
|
7
|
+
@api_token = api_token
|
8
|
+
@url = url
|
9
|
+
@status = "Active"
|
10
|
+
end
|
11
|
+
|
12
|
+
def insight_getstatus(uuid)
|
13
|
+
response = HTTParty.get(
|
14
|
+
"https://#{@url}/export/status/#{uuid}",
|
15
|
+
:basic_auth => { :username => @api_token })
|
16
|
+
if response.code == 200
|
17
|
+
parsed = JSON.parse(response.body)
|
18
|
+
return parsed
|
19
|
+
#error handing here
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def data_export_insights_file(objecttype, segmentuuid, startDate, endDate, tries: 30)
|
24
|
+
status = data_export_insights(objecttype, segmentuuid, startDate, endDate, tries: tries)
|
25
|
+
if status['status']== "COMPLETE"
|
26
|
+
signedUrl = status['signedUrl']
|
27
|
+
return get_file(file_name: "insights-#{startDate}-#{endDate}.csv", url: signedUrl, headers: {}, count: 3, file_type: "zip")
|
28
|
+
else
|
29
|
+
return status
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def data_export_insights(objecttype, segmentuuid, startDate, endDate, tries: 30)
|
34
|
+
status = insights_fetch_all(objecttype, segmentuuid, startDate, endDate)
|
35
|
+
if status['uuid'] == nil
|
36
|
+
return "Failed: #{status["response"]}"
|
37
|
+
else
|
38
|
+
fileid = status['uuid']
|
39
|
+
end
|
40
|
+
for retries in 1..tries
|
41
|
+
status = insight_getstatus(fileid)
|
42
|
+
if status['status']== "COMPLETE"
|
43
|
+
signedUrl = status['signedUrl']
|
44
|
+
return status
|
45
|
+
elsif status['status'] == "FAILED"
|
46
|
+
return status
|
47
|
+
else
|
48
|
+
sleep(60)
|
49
|
+
retries+=1
|
50
|
+
end
|
51
|
+
if retries > tries - 1
|
52
|
+
return "Timeout"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
return signedUrl
|
56
|
+
end
|
57
|
+
|
58
|
+
def insights_fetch_all(objecttype, segmentuuid, startDate, endDate)
|
59
|
+
if segmentuuid.is_a? Array
|
60
|
+
segmentsForAPI = segmentuuid.join('","')
|
61
|
+
elsif segmentuuid.is_a? String
|
62
|
+
segmentsForAPI = segmentuuid
|
63
|
+
elsif segmentuuid.is_a? Integer
|
64
|
+
segmentsForAPI = segmentuuid.to_s
|
65
|
+
else
|
66
|
+
raise "Error fetching Insights data: Segmentuuid must be either an array of uuids or an single uuid in string or interger format."
|
67
|
+
end
|
68
|
+
|
69
|
+
response = HTTParty.post(
|
70
|
+
"https://#{@url}/export/type/#{objecttype}",
|
71
|
+
:basic_auth => { :username => @api_token },
|
72
|
+
:headers => {'Content-Type'=> "Application/json"},
|
73
|
+
:body =>
|
74
|
+
'
|
75
|
+
{
|
76
|
+
"endDate": "' + (dateFormat(date: endDate)).to_s + '",
|
77
|
+
"startDate":"' + (dateFormat(date: startDate)).to_s + '",
|
78
|
+
"segments": [
|
79
|
+
"'+segmentsForAPI+'"
|
80
|
+
]
|
81
|
+
}
|
82
|
+
')
|
83
|
+
if response.code == 200
|
84
|
+
parsed = JSON.parse(response.body)
|
85
|
+
return parsed
|
86
|
+
else
|
87
|
+
return {"uuid"=> nil, "status"=>"Error", "signedUrl"=>"signedUrl", "response" => response.body}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def dateFormat(date: nil)
|
92
|
+
date ||= DateTime.now
|
93
|
+
if date.is_a? String
|
94
|
+
if date.include? "T"
|
95
|
+
return (date.to_datetime).to_s
|
96
|
+
else
|
97
|
+
return (date.to_date).to_s + "T#{DateTime.now.to_s(:time)}:00Z"
|
98
|
+
end
|
99
|
+
elsif date.instance_of?(DateTime)
|
100
|
+
return date.to_s
|
101
|
+
elsif date.instance_of?(Date)
|
102
|
+
return (date.to_date).to_s + "T#{DateTime.now.to_s(:time)}:00Z"
|
103
|
+
else
|
104
|
+
raise "Please pass in a in format of 'YYYY-MM-DD', 'YYYY-MM-DDT00:00:00+00:00' ruby Date, or ruby DateTime"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def upload_into_insights(dataSourceName, recordType, batchDate, filePath)
|
109
|
+
begin
|
110
|
+
temp_date = dateFormat(date: batchDate)
|
111
|
+
response = HTTParty.post(
|
112
|
+
"https://#{@url}/files/upload",
|
113
|
+
:basic_auth => { :username => @api_token }, :body => {
|
114
|
+
:dataSource => dataSourceName, :recordType => recordType,
|
115
|
+
:batchDate => temp_date})
|
116
|
+
parsed = JSON.parse(response.body)
|
117
|
+
signedUrl = parsed['signedUrl']
|
118
|
+
if !File.extname(filePath) == ".gz"
|
119
|
+
zipPath = gzip_file(filePath)
|
120
|
+
else
|
121
|
+
zipPath = filePath
|
122
|
+
end
|
123
|
+
|
124
|
+
gzippedFile = File.open(zipPath)
|
125
|
+
post = HTTParty.put(signedUrl,
|
126
|
+
:body => gzippedFile.read)
|
127
|
+
if post.code == 200
|
128
|
+
return {"status"=>"COMPLETE", "signedUrl"=>"#{signedUrl}", "response" => post.code, "batchDate" => "#{temp_date}"}
|
129
|
+
else
|
130
|
+
return {"status"=>"Error", "signedUrl"=>"#{signedUrl}", "response" => post.code, "message"=> "#{post.message}", "batchDate" => "#{temp_date}"}
|
131
|
+
end
|
132
|
+
rescue Exception => e
|
133
|
+
Rails.logger.debug "[ZuoraGem]: While uploading to insights Error: #{e}"
|
134
|
+
raise e
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def describe(type: "ACCOUNT", object: "attributes")
|
139
|
+
url = "https://#{@url}/export/#{object}/#{type}"
|
140
|
+
uri = URI.parse(url)
|
141
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
142
|
+
http.use_ssl = true
|
143
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
144
|
+
begin
|
145
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
146
|
+
request.basic_auth(@api_token, "")
|
147
|
+
return http.request(request)
|
148
|
+
rescue Exception => e
|
149
|
+
Rails.logger.debug "[ZuoraGem]: While describing Zoura Insights objects: #{e}"
|
150
|
+
return "Failed"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def get_file(file_name: nil, url: nil, basic: {:username => nil, :password => nil}, headers: {}, count: 3, file_type: "zip")
|
155
|
+
tries ||= 2
|
156
|
+
temp_file = nil
|
157
|
+
uri = URI(url)
|
158
|
+
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
|
159
|
+
request = Net::HTTP::Get.new(uri)
|
160
|
+
headers.each do |k,v|
|
161
|
+
request["#{k}"] = v
|
162
|
+
end
|
163
|
+
request.basic_auth(basic[:username], basic[:password]) if (!basic[:username].blank? && !basic[:password].blank?)
|
164
|
+
http.request request do |response|
|
165
|
+
case response
|
166
|
+
when Net::HTTPNotFound
|
167
|
+
Rails.logger.fatal("[ZuoraGem]: 404 - Not Found")
|
168
|
+
raise response
|
169
|
+
|
170
|
+
when Net::HTTPUnauthorized
|
171
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(zuora_client.current_error) if count <= 0
|
172
|
+
Rails.logger.fatal("[ZuoraGem]: Retry")
|
173
|
+
zuora_client.new_session
|
174
|
+
return get_file(:url => url, :count => count - 1, :headers => headers)
|
175
|
+
|
176
|
+
when Net::HTTPClientError
|
177
|
+
Rails.logger.debug("[ZuoraGem]: #{response}")
|
178
|
+
raise response
|
179
|
+
|
180
|
+
when Net::HTTPOK
|
181
|
+
Tempfile.open([file_name.rpartition('.').first, ".#{file_name.rpartition('.').last}"], "#{Rails.root}/tmp") do |tmp_file|
|
182
|
+
temp_file ||= tmp_file
|
183
|
+
tmp_file.binmode if (response.to_hash["content-type"].include?("application/zip") || response.to_hash["content-type"] == "application/zip")
|
184
|
+
response.read_body do |chunk|
|
185
|
+
tmp_file.write chunk.force_encoding("UTF-8")
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
rescue => ex
|
193
|
+
if !(tries -= 1).zero?
|
194
|
+
sleep 3
|
195
|
+
retry
|
196
|
+
else
|
197
|
+
raise ex
|
198
|
+
end
|
199
|
+
else
|
200
|
+
return temp_file
|
201
|
+
end
|
202
|
+
|
203
|
+
def gzip_file(filePath)
|
204
|
+
require "zip"
|
205
|
+
Zlib::GzipWriter.open(filePath + ".gz") do |gzip|
|
206
|
+
open(filePath, "rb") do |f|
|
207
|
+
f.each_chunk() {|chunk| gzip.write chunk }
|
208
|
+
end
|
209
|
+
gzip.close
|
210
|
+
end
|
211
|
+
return filePath+ ".gz"
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
class File
|
218
|
+
def each_chunk(chunk_size=2**16)
|
219
|
+
yield read(chunk_size) until eof?
|
220
|
+
end
|
221
|
+
end
|