generatepdfs 1.0.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +12 -0
- data/CONTRIBUTING.md +15 -0
- data/LICENSE +21 -0
- data/README.md +175 -0
- data/lib/generatepdfs/exceptions/invalid_argument_exception.rb +6 -0
- data/lib/generatepdfs/exceptions/runtime_exception.rb +6 -0
- data/lib/generatepdfs/generate_pdfs.rb +231 -0
- data/lib/generatepdfs/pdf.rb +103 -0
- data/lib/generatepdfs/version.rb +5 -0
- data/lib/generatepdfs.rb +10 -0
- metadata +148 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 91475bc0ce1e8d67a9c11a62cd46fcbf5cdd5c17f43dd6aca4f246cac4eb7035
|
|
4
|
+
data.tar.gz: 814033fc9ab61491cccd1c39c6c2dda428d6c3d2d08e7103b1ab7728e4277a07
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: fccdcb2b89722e4faa7d10614085b01c6900c0da42c65c84571b7546a88a994349f429104e238547a752064919faaa18e209edb3ae343e064d1c9f7d710ef929
|
|
7
|
+
data.tar.gz: 9414cbc050cde53fd62dc694f33cb926ae3e4783f34c973c0bdcc3b24e5b1b898af5db795d3030515818d73ba4261b740fa4355e3d0be520361a811f2a27cfb3
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Change log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [1.0.0] - 2026-01-01
|
|
7
|
+
|
|
8
|
+
* Support for uploading HTML/CSS/Images to generate PDF
|
|
9
|
+
* Support for submitting a URL to generate PDF
|
|
10
|
+
* Support for downloading and saving PDF from the API
|
|
11
|
+
* Support for getting PDF data from PDF id
|
|
12
|
+
* 100% Test coverage
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Contributions and suggestion are **welcome** and will be fully **credited**.
|
|
4
|
+
|
|
5
|
+
We accept contributions via Pull Requests on [Github](https://github.com/GeneratePDFs/ruby-sdk).
|
|
6
|
+
|
|
7
|
+
## Pull Requests
|
|
8
|
+
|
|
9
|
+
- **Follow Ruby style guide** - Use RuboCop to ensure code style consistency
|
|
10
|
+
- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
|
|
11
|
+
- **Document any change in behaviour** - Make sure the README / CHANGELOG and any other relevant documentation are kept up-to-date.
|
|
12
|
+
- **Consider our release cycle** - We try to follow semver. Randomly breaking public APIs is not an option.
|
|
13
|
+
- **Create topic branches** - Don't ask us to pull from your master branch.
|
|
14
|
+
- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
|
|
15
|
+
- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 GeneratePDFs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# GeneratePDFs Ruby SDK
|
|
2
|
+
|
|
3
|
+
Ruby SDK for the [GeneratePDFs.com](https://generatepdfs.com) API, your go-to place for HTML to PDF.
|
|
4
|
+
|
|
5
|
+
Upload your HTML files, along with any CSS files and images to generate a PDF. Alternatively provide a URL to generate a PDF from it's contents.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add this line to your application's Gemfile:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem 'generatepdfs'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
And then execute:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bundle install
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or install it yourself as:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
gem install generatepdfs
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Get your API Token
|
|
28
|
+
|
|
29
|
+
Sign up for an account on [GeneratePDFs.com](https://generatepdfs.com) and head to the API Tokens section and create a new token.
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Basic Setup
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
require 'generatepdfs'
|
|
37
|
+
|
|
38
|
+
client = GeneratePDFs::GeneratePDFs.connect('YOUR_API_TOKEN')
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Generate PDF from HTML File
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
require 'generatepdfs'
|
|
45
|
+
|
|
46
|
+
# Simple HTML file
|
|
47
|
+
pdf = client.generate_from_html('/path/to/file.html')
|
|
48
|
+
|
|
49
|
+
# HTML file with CSS
|
|
50
|
+
pdf = client.generate_from_html(
|
|
51
|
+
'/path/to/file.html',
|
|
52
|
+
'/path/to/file.css'
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# HTML file with CSS and images
|
|
56
|
+
pdf = client.generate_from_html(
|
|
57
|
+
'/path/to/file.html',
|
|
58
|
+
'/path/to/file.css',
|
|
59
|
+
[
|
|
60
|
+
{
|
|
61
|
+
name: 'logo.png',
|
|
62
|
+
path: '/path/to/logo.png',
|
|
63
|
+
mime_type: 'image/png' # Optional, will be auto-detected
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'photo.jpg',
|
|
67
|
+
path: '/path/to/photo.jpg'
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Generate PDF from URL
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
pdf = client.generate_from_url('https://example.com')
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Get PDF by ID
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
# Retrieve a PDF by its ID
|
|
83
|
+
pdf = client.get_pdf(123)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Working with PDF Objects
|
|
87
|
+
|
|
88
|
+
The SDK returns `Pdf` objects that provide easy access to PDF information and downloading:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
# Access PDF properties
|
|
92
|
+
pdf_id = pdf.id
|
|
93
|
+
pdf_name = pdf.name
|
|
94
|
+
status = pdf.status
|
|
95
|
+
download_url = pdf.download_url
|
|
96
|
+
created_at = pdf.created_at
|
|
97
|
+
|
|
98
|
+
# Check if PDF is ready
|
|
99
|
+
if pdf.ready?
|
|
100
|
+
# Download PDF content as string
|
|
101
|
+
pdf_content = pdf.download
|
|
102
|
+
|
|
103
|
+
# Or save directly to file
|
|
104
|
+
pdf.download_to_file('/path/to/save/output.pdf')
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Refresh PDF data from the API (useful for checking status updates)
|
|
108
|
+
refreshed_pdf = pdf.refresh
|
|
109
|
+
if refreshed_pdf.ready?
|
|
110
|
+
pdf_content = refreshed_pdf.download
|
|
111
|
+
end
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Client Methods
|
|
115
|
+
|
|
116
|
+
- `generate_from_html(html_path, css_path = nil, images = [])` - Generate a PDF from HTML file(s)
|
|
117
|
+
- `generate_from_url(url)` - Generate a PDF from a URL
|
|
118
|
+
- `get_pdf(id)` - Retrieve a PDF by its ID
|
|
119
|
+
- `download_pdf(download_url)` - Download PDF binary content from a download URL
|
|
120
|
+
|
|
121
|
+
### PDF Object Methods
|
|
122
|
+
|
|
123
|
+
- `id` - Get the PDF ID
|
|
124
|
+
- `name` - Get the PDF filename
|
|
125
|
+
- `status` - Get the current status (pending, processing, completed, failed)
|
|
126
|
+
- `download_url` - Get the download URL
|
|
127
|
+
- `created_at` - Get the creation date
|
|
128
|
+
- `ready?` - Check if the PDF is ready for download
|
|
129
|
+
- `download` - Download and return PDF binary content
|
|
130
|
+
- `download_to_file(file_path)` - Download and save PDF to a file
|
|
131
|
+
- `refresh` - Refresh PDF data from the API and return a new Pdf instance with updated information
|
|
132
|
+
|
|
133
|
+
## Requirements
|
|
134
|
+
|
|
135
|
+
- Ruby 3.0 or higher
|
|
136
|
+
- Faraday 2.0 or higher
|
|
137
|
+
- MIME::Types 3.0 or higher
|
|
138
|
+
|
|
139
|
+
## Testing
|
|
140
|
+
|
|
141
|
+
To run the test suite, execute:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
bundle exec rspec
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
To run tests with coverage:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
bundle exec rspec --format documentation
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Contributing
|
|
154
|
+
|
|
155
|
+
Contributions and suggestions are **welcome** and will be fully **credited**.
|
|
156
|
+
|
|
157
|
+
We accept contributions via Pull Requests on [GitHub](https://github.com/GeneratePDFs/ruby-sdk).
|
|
158
|
+
|
|
159
|
+
### Pull Requests
|
|
160
|
+
|
|
161
|
+
- **Follow Ruby style guide** - Use RuboCop to ensure code style consistency
|
|
162
|
+
- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
|
|
163
|
+
- **Document any change in behaviour** - Make sure the README / CHANGELOG and any other relevant documentation are kept up-to-date.
|
|
164
|
+
- **Consider our release cycle** - We try to follow semver. Randomly breaking public APIs is not an option.
|
|
165
|
+
- **Create topic branches** - Don't ask us to pull from your master branch.
|
|
166
|
+
- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
|
|
167
|
+
- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting.
|
|
168
|
+
|
|
169
|
+
## Changelog
|
|
170
|
+
|
|
171
|
+
See [CHANGELOG.md](CHANGELOG.md) for a history of changes.
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'faraday'
|
|
4
|
+
require 'base64'
|
|
5
|
+
require 'json'
|
|
6
|
+
require 'uri'
|
|
7
|
+
require 'mime/types'
|
|
8
|
+
require_relative 'pdf'
|
|
9
|
+
require_relative 'exceptions/invalid_argument_exception'
|
|
10
|
+
require_relative 'exceptions/runtime_exception'
|
|
11
|
+
|
|
12
|
+
module GeneratePDFs
|
|
13
|
+
# Main client class for interacting with the GeneratePDFs API
|
|
14
|
+
class GeneratePDFs
|
|
15
|
+
BASE_URL = 'https://api.generatepdfs.com'
|
|
16
|
+
|
|
17
|
+
# Create a new GeneratePDFs instance with the provided API token.
|
|
18
|
+
#
|
|
19
|
+
# @param api_token [String] The API token for authentication
|
|
20
|
+
# @return [GeneratePDFs] A new GeneratePDFs instance
|
|
21
|
+
def self.connect(api_token)
|
|
22
|
+
new(api_token)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Initialize a new GeneratePDFs client
|
|
26
|
+
#
|
|
27
|
+
# @param api_token [String] The API token for authentication
|
|
28
|
+
def initialize(api_token)
|
|
29
|
+
@api_token = api_token
|
|
30
|
+
@client = Faraday.new(
|
|
31
|
+
url: BASE_URL,
|
|
32
|
+
headers: {
|
|
33
|
+
'Content-Type' => 'application/json'
|
|
34
|
+
}
|
|
35
|
+
) do |conn|
|
|
36
|
+
conn.request :json
|
|
37
|
+
conn.response :json
|
|
38
|
+
conn.adapter Faraday.default_adapter
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Generate a PDF from HTML file(s) with optional CSS and images.
|
|
43
|
+
#
|
|
44
|
+
# @param html_path [String] Path to the HTML file
|
|
45
|
+
# @param css_path [String, nil] Optional path to the CSS file
|
|
46
|
+
# @param images [Array<Hash>] Optional array of image files with keys: :name, :path, :mime_type
|
|
47
|
+
# @return [Pdf] PDF object containing PDF information
|
|
48
|
+
# @raise [InvalidArgumentException] If files are invalid
|
|
49
|
+
def generate_from_html(html_path, css_path = nil, images = [])
|
|
50
|
+
unless File.exist?(html_path) && File.readable?(html_path)
|
|
51
|
+
raise InvalidArgumentException, "HTML file not found or not readable: #{html_path}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
html_content = Base64.strict_encode64(File.read(html_path))
|
|
55
|
+
|
|
56
|
+
data = {
|
|
57
|
+
html: html_content
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if css_path
|
|
61
|
+
unless File.exist?(css_path) && File.readable?(css_path)
|
|
62
|
+
raise InvalidArgumentException, "CSS file not found or not readable: #{css_path}"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
data[:css] = Base64.strict_encode64(File.read(css_path))
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
data[:images] = process_images(images) unless images.empty?
|
|
69
|
+
|
|
70
|
+
response = make_request('/pdfs/generate', data)
|
|
71
|
+
|
|
72
|
+
data_hash = response['data'] || response[:data]
|
|
73
|
+
unless data_hash
|
|
74
|
+
raise InvalidArgumentException, 'Invalid API response: missing data'
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
Pdf.from_hash(data_hash, self)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Generate a PDF from a URL.
|
|
81
|
+
#
|
|
82
|
+
# @param url [String] The URL to convert to PDF
|
|
83
|
+
# @return [Pdf] PDF object containing PDF information
|
|
84
|
+
# @raise [InvalidArgumentException] If URL is invalid
|
|
85
|
+
def generate_from_url(url)
|
|
86
|
+
begin
|
|
87
|
+
uri = URI.parse(url)
|
|
88
|
+
raise InvalidArgumentException, "Invalid URL: #{url}" unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
|
|
89
|
+
rescue URI::InvalidURIError
|
|
90
|
+
raise InvalidArgumentException, "Invalid URL: #{url}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
data = {
|
|
94
|
+
url: url
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
response = make_request('/pdfs/generate', data)
|
|
98
|
+
|
|
99
|
+
data_hash = response['data'] || response[:data]
|
|
100
|
+
unless data_hash
|
|
101
|
+
raise InvalidArgumentException, 'Invalid API response: missing data'
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
Pdf.from_hash(data_hash, self)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Get a PDF by its ID.
|
|
108
|
+
#
|
|
109
|
+
# @param id [Integer] The PDF ID
|
|
110
|
+
# @return [Pdf] PDF object containing PDF information
|
|
111
|
+
# @raise [InvalidArgumentException] If ID is invalid
|
|
112
|
+
def get_pdf(id)
|
|
113
|
+
if id <= 0
|
|
114
|
+
raise InvalidArgumentException, "Invalid PDF ID: #{id}"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
response = make_get_request("/pdfs/#{id}")
|
|
118
|
+
|
|
119
|
+
data_hash = response['data'] || response[:data]
|
|
120
|
+
unless data_hash
|
|
121
|
+
raise InvalidArgumentException, 'Invalid API response: missing data'
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
Pdf.from_hash(data_hash, self)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Download a PDF from the API.
|
|
128
|
+
#
|
|
129
|
+
# @param download_url [String] The download URL for the PDF
|
|
130
|
+
# @return [String] PDF binary content
|
|
131
|
+
def download_pdf(download_url)
|
|
132
|
+
response = @client.get(download_url) do |req|
|
|
133
|
+
req.headers['Authorization'] = "Bearer #{@api_token}"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
raise RuntimeException, "Failed to download PDF: #{response.status}" unless response.success?
|
|
137
|
+
|
|
138
|
+
response.body
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
private
|
|
142
|
+
|
|
143
|
+
# Process image files and return formatted array for API.
|
|
144
|
+
#
|
|
145
|
+
# @param images [Array<Hash>] Array of image inputs with keys: :name, :path, :mime_type
|
|
146
|
+
# @return [Array<Hash>] Array of processed images
|
|
147
|
+
def process_images(images)
|
|
148
|
+
processed = []
|
|
149
|
+
|
|
150
|
+
images.each do |image|
|
|
151
|
+
next unless image[:path] && image[:name]
|
|
152
|
+
|
|
153
|
+
path = image[:path]
|
|
154
|
+
name = image[:name]
|
|
155
|
+
|
|
156
|
+
next unless File.exist?(path) && File.readable?(path)
|
|
157
|
+
|
|
158
|
+
content = Base64.strict_encode64(File.read(path))
|
|
159
|
+
|
|
160
|
+
# Detect mime type if not provided
|
|
161
|
+
mime_type = image[:mime_type] || detect_mime_type(path)
|
|
162
|
+
|
|
163
|
+
processed << {
|
|
164
|
+
name: name,
|
|
165
|
+
content: content,
|
|
166
|
+
mime_type: mime_type
|
|
167
|
+
}
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
processed
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Detect MIME type of a file.
|
|
174
|
+
#
|
|
175
|
+
# @param file_path [String] Path to the file
|
|
176
|
+
# @return [String] MIME type
|
|
177
|
+
def detect_mime_type(file_path)
|
|
178
|
+
mime_type = MIME::Types.type_for(file_path).first
|
|
179
|
+
return mime_type.to_s if mime_type
|
|
180
|
+
|
|
181
|
+
# Fallback to extension-based detection
|
|
182
|
+
extension = File.extname(file_path).downcase.delete_prefix('.')
|
|
183
|
+
mime_types = {
|
|
184
|
+
'jpg' => 'image/jpeg',
|
|
185
|
+
'jpeg' => 'image/jpeg',
|
|
186
|
+
'png' => 'image/png',
|
|
187
|
+
'gif' => 'image/gif',
|
|
188
|
+
'webp' => 'image/webp',
|
|
189
|
+
'svg' => 'image/svg+xml'
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
mime_types[extension] || 'application/octet-stream'
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Make an HTTP POST request to the API.
|
|
196
|
+
#
|
|
197
|
+
# @param endpoint [String] API endpoint
|
|
198
|
+
# @param data [Hash] Request data
|
|
199
|
+
# @return [Hash] Decoded JSON response
|
|
200
|
+
def make_request(endpoint, data)
|
|
201
|
+
response = @client.post(endpoint) do |req|
|
|
202
|
+
req.headers['Authorization'] = "Bearer #{@api_token}"
|
|
203
|
+
req.body = data.to_json
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
unless response.success?
|
|
207
|
+
error_msg = response.reason_phrase || response.status.to_s
|
|
208
|
+
raise RuntimeException, "API request failed: #{response.status} #{error_msg}"
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
response.body.is_a?(Hash) ? response.body : JSON.parse(response.body)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Make an HTTP GET request to the API.
|
|
215
|
+
#
|
|
216
|
+
# @param endpoint [String] API endpoint
|
|
217
|
+
# @return [Hash] Decoded JSON response
|
|
218
|
+
def make_get_request(endpoint)
|
|
219
|
+
response = @client.get(endpoint) do |req|
|
|
220
|
+
req.headers['Authorization'] = "Bearer #{@api_token}"
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
unless response.success?
|
|
224
|
+
error_msg = response.reason_phrase || response.status.to_s
|
|
225
|
+
raise RuntimeException, "API request failed: #{response.status} #{error_msg}"
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
response.body.is_a?(Hash) ? response.body : JSON.parse(response.body)
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'time'
|
|
4
|
+
require_relative 'exceptions/invalid_argument_exception'
|
|
5
|
+
require_relative 'exceptions/runtime_exception'
|
|
6
|
+
|
|
7
|
+
module GeneratePDFs
|
|
8
|
+
# PDF object representing a PDF document from the API
|
|
9
|
+
class Pdf
|
|
10
|
+
attr_reader :id, :name, :status, :download_url, :created_at
|
|
11
|
+
|
|
12
|
+
# Create a Pdf instance from API response data.
|
|
13
|
+
#
|
|
14
|
+
# @param data [Hash] API response data with keys: id, name, status, download_url, created_at
|
|
15
|
+
# @param client [GeneratePDFs] The GeneratePDFs client instance
|
|
16
|
+
# @return [Pdf] A new Pdf instance
|
|
17
|
+
# @raise [InvalidArgumentException] If data structure is invalid
|
|
18
|
+
def self.from_hash(data, client)
|
|
19
|
+
# Normalize keys to symbols for easier access
|
|
20
|
+
normalized_data = data.transform_keys(&:to_sym)
|
|
21
|
+
|
|
22
|
+
required_keys = %i[id name status download_url created_at]
|
|
23
|
+
missing_keys = required_keys - normalized_data.keys
|
|
24
|
+
|
|
25
|
+
unless missing_keys.empty?
|
|
26
|
+
raise InvalidArgumentException, 'Invalid PDF data structure'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Parse the created_at date
|
|
30
|
+
begin
|
|
31
|
+
created_at = Time.parse(normalized_data[:created_at].to_s)
|
|
32
|
+
rescue ArgumentError
|
|
33
|
+
raise InvalidArgumentException, "Invalid created_at format: #{normalized_data[:created_at]}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
new(
|
|
37
|
+
normalized_data[:id].to_i,
|
|
38
|
+
normalized_data[:name].to_s,
|
|
39
|
+
normalized_data[:status].to_s,
|
|
40
|
+
normalized_data[:download_url].to_s,
|
|
41
|
+
created_at,
|
|
42
|
+
client
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Initialize a new Pdf instance
|
|
47
|
+
#
|
|
48
|
+
# @param id [Integer] PDF ID
|
|
49
|
+
# @param name [String] PDF name
|
|
50
|
+
# @param status [String] PDF status
|
|
51
|
+
# @param download_url [String] Download URL
|
|
52
|
+
# @param created_at [Time] Creation date
|
|
53
|
+
# @param client [GeneratePDFs] The GeneratePDFs client instance
|
|
54
|
+
def initialize(id, name, status, download_url, created_at, client)
|
|
55
|
+
@id = id
|
|
56
|
+
@name = name
|
|
57
|
+
@status = status
|
|
58
|
+
@download_url = download_url
|
|
59
|
+
@created_at = created_at
|
|
60
|
+
@client = client
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Check if the PDF is ready for download.
|
|
64
|
+
#
|
|
65
|
+
# @return [Boolean] True if PDF is ready
|
|
66
|
+
def ready?
|
|
67
|
+
@status == 'completed'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Download the PDF content.
|
|
71
|
+
#
|
|
72
|
+
# @return [String] PDF binary content
|
|
73
|
+
# @raise [RuntimeException] If the PDF is not ready or download fails
|
|
74
|
+
def download
|
|
75
|
+
unless ready?
|
|
76
|
+
raise RuntimeException, "PDF is not ready yet. Current status: #{@status}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
@client.download_pdf(@download_url)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Download the PDF and save it to a file.
|
|
83
|
+
#
|
|
84
|
+
# @param file_path [String] Path where to save the PDF file
|
|
85
|
+
# @return [Boolean] True on success
|
|
86
|
+
# @raise [RuntimeException] If the PDF is not ready or download fails
|
|
87
|
+
def download_to_file(file_path)
|
|
88
|
+
content = download
|
|
89
|
+
|
|
90
|
+
File.binwrite(file_path, content)
|
|
91
|
+
true
|
|
92
|
+
rescue StandardError => e
|
|
93
|
+
raise RuntimeException, "Failed to write PDF to file: #{file_path} - #{e.message}"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Refresh the PDF data from the API.
|
|
97
|
+
#
|
|
98
|
+
# @return [Pdf] A new Pdf instance with updated data
|
|
99
|
+
def refresh
|
|
100
|
+
@client.get_pdf(@id)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
data/lib/generatepdfs.rb
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'generatepdfs/version'
|
|
4
|
+
require_relative 'generatepdfs/generate_pdfs'
|
|
5
|
+
require_relative 'generatepdfs/pdf'
|
|
6
|
+
require_relative 'generatepdfs/exceptions/invalid_argument_exception'
|
|
7
|
+
require_relative 'generatepdfs/exceptions/runtime_exception'
|
|
8
|
+
|
|
9
|
+
module GeneratePDFs
|
|
10
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: generatepdfs
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- GeneratePDFs
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: base64
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: faraday
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '2.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '2.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: mime-types
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '3.0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '3.0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rspec
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '3.12'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '3.12'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: webmock
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '3.18'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '3.18'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: rubocop
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '1.57'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '1.57'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: rubocop-rspec
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '2.25'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '2.25'
|
|
110
|
+
description: Ruby SDK for the GeneratePDFs.com API, your go-to place for HTML to PDF.
|
|
111
|
+
email:
|
|
112
|
+
- info@generatepdfs.com
|
|
113
|
+
executables: []
|
|
114
|
+
extensions: []
|
|
115
|
+
extra_rdoc_files: []
|
|
116
|
+
files:
|
|
117
|
+
- CHANGELOG.md
|
|
118
|
+
- CONTRIBUTING.md
|
|
119
|
+
- LICENSE
|
|
120
|
+
- README.md
|
|
121
|
+
- lib/generatepdfs.rb
|
|
122
|
+
- lib/generatepdfs/exceptions/invalid_argument_exception.rb
|
|
123
|
+
- lib/generatepdfs/exceptions/runtime_exception.rb
|
|
124
|
+
- lib/generatepdfs/generate_pdfs.rb
|
|
125
|
+
- lib/generatepdfs/pdf.rb
|
|
126
|
+
- lib/generatepdfs/version.rb
|
|
127
|
+
homepage: https://github.com/GeneratePDFs/ruby-sdk
|
|
128
|
+
licenses:
|
|
129
|
+
- MIT
|
|
130
|
+
metadata: {}
|
|
131
|
+
rdoc_options: []
|
|
132
|
+
require_paths:
|
|
133
|
+
- lib
|
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: 3.0.0
|
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
|
+
requirements:
|
|
141
|
+
- - ">="
|
|
142
|
+
- !ruby/object:Gem::Version
|
|
143
|
+
version: '0'
|
|
144
|
+
requirements: []
|
|
145
|
+
rubygems_version: 4.0.3
|
|
146
|
+
specification_version: 4
|
|
147
|
+
summary: Ruby SDK for GeneratePDFs.com API
|
|
148
|
+
test_files: []
|