zuora_api_D 1.6.06
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.
- 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_api.rb +9 -0
- data/lib/zuora_api/exceptions.rb +106 -0
- data/lib/zuora_api/login.rb +808 -0
- data/lib/zuora_api/logins/basic.rb +103 -0
- data/lib/zuora_api/logins/oauth.rb +106 -0
- data/lib/zuora_api/version.rb +3 -0
- data/zuora_api.gemspec +30 -0
- metadata +193 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0a408b85ca45825733c30c623994f5f736b7982b18258db77b723f9a53000344
|
4
|
+
data.tar.gz: 7f0f79b372f2383f8133324798b8bb442ceb6eedf36d22f64174415016fc941e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d07bec2378404b0cf4342fb8e52c9a3b9ad0d2f141ecca6bc4eca61c6c4e36e84c61fc5d430a95c19e3a7b8cf8672ba03b5812d602dc078bba9882db07b06bac
|
7
|
+
data.tar.gz: 6676504c96ce47af6ccaafe56241aaf1e05eed62dc9ba9274acf00f615dba1c78319b764b8eb6386bd4625fde8003c4f382c7f01715033e2d2d619164380b517
|
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
|
+
[](https://badge.fury.io/rb/zuora_api) [](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_api'
|
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
|