pdfmonkey 0.9.0 → 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.
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'json'
5
+
6
+ module Pdfmonkey
7
+ class Resource
8
+ extend Forwardable
9
+
10
+ module Fetchable
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+
15
+ module ClassMethods
16
+ def fetch(id)
17
+ new(id: id).reload!
18
+ end
19
+ end
20
+
21
+ def reload!
22
+ new_attrs = adapter.call(:get, self)
23
+ update(new_attrs)
24
+ self
25
+ end
26
+ end
27
+
28
+ module Creatable
29
+ def self.included(base)
30
+ base.extend(ClassMethods)
31
+ end
32
+
33
+ module ClassMethods
34
+ def create(**attrs)
35
+ new(**attrs).save
36
+ end
37
+ end
38
+
39
+ def save
40
+ if attributes[:id] && !is_a?(Updatable)
41
+ raise Pdfmonkey::Error, "Cannot save an existing #{self.class.name} (updates are not supported)"
42
+ end
43
+
44
+ method = attributes[:id] ? :put : :post
45
+ new_attrs = adapter.call(method, self)
46
+ update(new_attrs)
47
+ self
48
+ end
49
+ end
50
+
51
+ module Updatable
52
+ def update!(**new_attrs)
53
+ previous = {}
54
+ new_attrs.each_key do |key|
55
+ sym_key = key.to_sym
56
+ previous[sym_key] = attributes[sym_key] if self.class::ATTRIBUTES.include?(sym_key)
57
+ end
58
+
59
+ update(new_attrs)
60
+ response_attrs = adapter.call(:put, self)
61
+ update(response_attrs)
62
+ self
63
+ rescue StandardError
64
+ update(previous)
65
+ raise
66
+ end
67
+ end
68
+
69
+ module Deletable
70
+ def self.included(base)
71
+ base.extend(ClassMethods)
72
+ end
73
+
74
+ module ClassMethods
75
+ def delete(id)
76
+ new(id: id).delete!
77
+ end
78
+ end
79
+
80
+ def delete!
81
+ adapter.call(:delete, self)
82
+ end
83
+ end
84
+
85
+ module Listable
86
+ def self.included(base)
87
+ base.extend(ClassMethods)
88
+ end
89
+
90
+ module ClassMethods
91
+ def list(page: 'all', **filters)
92
+ if const_defined?(:FILTERS, false)
93
+ unknown = filters.keys - self::FILTERS.keys
94
+ raise ArgumentError, "Unknown filter(s): #{unknown.join(', ')}" if unknown.any?
95
+ elsif filters.any?
96
+ raise ArgumentError, "#{name} does not support filters"
97
+ end
98
+
99
+ adapter = Pdfmonkey.current_adapter || Pdfmonkey::Adapter.new
100
+ fetch_page(adapter, page: page, **filters)
101
+ end
102
+
103
+ private def fetch_page(adapter, page:, **filters)
104
+ params = { 'page[number]' => page }
105
+
106
+ if const_defined?(:FILTERS, false)
107
+ self::FILTERS.each do |kwarg, api_param|
108
+ params[api_param] = filters[kwarg] unless filters[kwarg].nil?
109
+ end
110
+ end
111
+
112
+ body = adapter.call(:get, self, params: params, extract: :collection)
113
+
114
+ collection_key = self::COLLECTION
115
+ items = body.fetch(collection_key, []).map do |attrs|
116
+ resource_attrs = attrs.transform_keys(&:to_sym)
117
+ resource_attrs.delete(:adapter)
118
+ new(adapter: adapter, **resource_attrs)
119
+ end
120
+
121
+ page_fetcher = lambda do |page_number|
122
+ fetch_page(adapter, page: page_number, **filters)
123
+ end
124
+
125
+ Collection.new(
126
+ items: items,
127
+ meta: body.fetch('meta', {}),
128
+ page_fetcher: page_fetcher
129
+ )
130
+ end
131
+ end
132
+ end
133
+
134
+ def initialize(adapter: Pdfmonkey.current_adapter || Pdfmonkey::Adapter.new, **attrs)
135
+ @adapter = adapter
136
+ @attributes = self.class.attributes_struct.new
137
+ update(attrs)
138
+ end
139
+
140
+ def ==(other)
141
+ other.is_a?(self.class) && !attributes[:id].nil? && attributes[:id] == other.send(:attributes)[:id]
142
+ end
143
+ alias eql? ==
144
+
145
+ def hash
146
+ [self.class, attributes[:id] || object_id].hash
147
+ end
148
+
149
+ SENSITIVE_ATTRIBUTES = %i[auth_token].freeze
150
+
151
+ def inspect
152
+ attrs = self.class::ATTRIBUTES
153
+ .filter_map do |key|
154
+ next if attributes[key].nil?
155
+
156
+ value = SENSITIVE_ATTRIBUTES.include?(key) ? '[FILTERED]' : attributes[key].inspect
157
+ "#{key}: #{value}"
158
+ end
159
+ .join(', ')
160
+
161
+ "#<#{self.class} #{attrs}>"
162
+ end
163
+
164
+ def to_h
165
+ attributes.to_h
166
+ end
167
+
168
+ def to_json(state = nil)
169
+ attrs = attributes.to_h.compact
170
+ attrs.delete(:errors)
171
+
172
+ member = self.class::MEMBER
173
+ { member => attrs }.to_json(state)
174
+ end
175
+
176
+ ATTRIBUTES_STRUCT_MUTEX = Mutex.new
177
+ private_constant :ATTRIBUTES_STRUCT_MUTEX
178
+
179
+ def self.attributes_struct
180
+ return @attributes_struct if @attributes_struct
181
+
182
+ ATTRIBUTES_STRUCT_MUTEX.synchronize do
183
+ @attributes_struct ||= Struct.new(*self::ATTRIBUTES, keyword_init: true)
184
+ end
185
+ end
186
+
187
+ private attr_reader :adapter, :attributes
188
+
189
+ private def update(new_attributes)
190
+ valid_attrs = self.class::ATTRIBUTES
191
+ new_attributes.each do |key, value|
192
+ sym_key = key.to_sym
193
+ attributes[sym_key] = value if valid_attrs.include?(sym_key)
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfmonkey
4
+ class Snippet < Resource
5
+ include Fetchable
6
+ include Creatable
7
+ include Updatable
8
+ include Deletable
9
+ include Listable
10
+
11
+ ATTRIBUTES = %i[
12
+ code
13
+ created_at
14
+ creator_name
15
+ errors
16
+ id
17
+ identifier
18
+ updated_at
19
+ updater_name
20
+ workspace_id
21
+ ].freeze
22
+
23
+ COLLECTION = 'snippets'
24
+ MEMBER = 'snippet'
25
+
26
+ def_delegators :attributes, *ATTRIBUTES
27
+ end
28
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfmonkey
4
+ class Template < Resource
5
+ include Fetchable
6
+ include Creatable
7
+ include Updatable
8
+ include Deletable
9
+
10
+ ATTRIBUTES = %i[
11
+ app_id
12
+ auth_token
13
+ body
14
+ body_draft
15
+ checksum
16
+ created_at
17
+ deleted_at
18
+ edition_mode
19
+ errors
20
+ id
21
+ identifier
22
+ output_type
23
+ pdf_engine_draft_id
24
+ pdf_engine_id
25
+ preview_url
26
+ sample_data
27
+ sample_data_draft
28
+ scss_style
29
+ scss_style_draft
30
+ settings
31
+ settings_draft
32
+ template_folder_id
33
+ ttl
34
+ updated_at
35
+ ].freeze
36
+
37
+ DRAFT_MAPPING = {
38
+ body: :body_draft,
39
+ scss_style: :scss_style_draft,
40
+ settings: :settings_draft,
41
+ sample_data: :sample_data_draft,
42
+ pdf_engine_id: :pdf_engine_draft_id
43
+ }.freeze
44
+
45
+ COLLECTION = 'document_templates'
46
+ MEMBER = 'document_template'
47
+
48
+ def_delegators :attributes, *ATTRIBUTES
49
+
50
+ def self.create(**attrs)
51
+ super(**remap_to_draft(attrs))
52
+ end
53
+
54
+ def self.list_cards(**)
55
+ Pdfmonkey::TemplateCard.list(**)
56
+ end
57
+
58
+ def self.fetch_full(id)
59
+ fetch(id)
60
+ end
61
+
62
+ def update!(**new_attrs)
63
+ super(**self.class.send(:remap_to_draft, new_attrs))
64
+ end
65
+
66
+ def publish!
67
+ DRAFT_MAPPING.each do |published_key, draft_key|
68
+ attributes[published_key] = attributes[draft_key]
69
+ end
70
+
71
+ response_attrs = adapter.call(:put, self)
72
+ update(response_attrs)
73
+ self
74
+ end
75
+
76
+ private_class_method def self.remap_to_draft(attrs)
77
+ attrs.transform_keys { |k| DRAFT_MAPPING.fetch(k, k) }
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfmonkey
4
+ class TemplateCard < Resource
5
+ include Listable
6
+
7
+ ATTRIBUTES = %i[
8
+ app_id
9
+ auth_token
10
+ created_at
11
+ edition_mode
12
+ errors
13
+ id
14
+ identifier
15
+ is_draft
16
+ output_type
17
+ pdf_engine_deprecated_on
18
+ pdf_engine_name
19
+ template_folder_id
20
+ template_folder_identifier
21
+ updated_at
22
+ ].freeze
23
+
24
+ COLLECTION = 'document_template_cards'
25
+ MEMBER = 'document_template_card'
26
+
27
+ FILTERS = {
28
+ workspace_id: 'q[workspace_id]',
29
+ folders: 'q[folders]',
30
+ sort: 'sort'
31
+ }.freeze
32
+
33
+ def_delegators :attributes, *ATTRIBUTES
34
+
35
+ def self.list(workspace_id:, **)
36
+ super
37
+ end
38
+
39
+ def to_template
40
+ Pdfmonkey::Template.fetch(id)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfmonkey
4
+ class TemplateFolder < Resource
5
+ include Fetchable
6
+ include Creatable
7
+ include Updatable
8
+ include Deletable
9
+ include Listable
10
+
11
+ ATTRIBUTES = %i[
12
+ app_id
13
+ created_at
14
+ errors
15
+ id
16
+ identifier
17
+ updated_at
18
+ ].freeze
19
+
20
+ COLLECTION = 'template_folders'
21
+ MEMBER = 'template_folder'
22
+
23
+ def_delegators :attributes, *ATTRIBUTES
24
+ end
25
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pdfmonkey
4
- VERSION = '0.9.0'
4
+ VERSION = '1.0.0'
5
5
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfmonkey
4
+ class Webhook < Resource
5
+ include Creatable
6
+ include Deletable
7
+
8
+ ATTRIBUTES = %i[
9
+ created_at
10
+ custom_channel
11
+ document_template_ids
12
+ errors
13
+ event
14
+ id
15
+ platform
16
+ updated_at
17
+ url
18
+ workspace_id
19
+ ].freeze
20
+
21
+ COLLECTION = 'rest_hooks'
22
+ MEMBER = 'rest_hook'
23
+
24
+ def_delegators :attributes, *ATTRIBUTES
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfmonkey
4
+ class Workspace < Resource
5
+ include Fetchable
6
+ include Listable
7
+
8
+ ATTRIBUTES = %i[
9
+ errors
10
+ id
11
+ identifier
12
+ invite_token
13
+ ].freeze
14
+
15
+ COLLECTION = 'workspaces'
16
+ MEMBER = 'workspace'
17
+
18
+ def_delegators :attributes, *ATTRIBUTES
19
+
20
+ def self.list_cards(**)
21
+ list(**)
22
+ end
23
+ end
24
+ end
data/lib/pdfmonkey.rb CHANGED
@@ -1,11 +1,57 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pdfmonkey/adapter'
4
3
  require 'pdfmonkey/configuration'
5
- require 'pdfmonkey/document'
6
4
  require 'pdfmonkey/version'
7
5
 
8
6
  module Pdfmonkey
9
7
  class Error < StandardError; end
10
- # Your code goes here...
8
+
9
+ class ConnectionError < Error; end
10
+ class GenerationError < Error
11
+ attr_reader :document
12
+
13
+ def initialize(message, document:)
14
+ @document = document
15
+ super(message)
16
+ end
17
+ end
18
+
19
+ class ApiError < Error
20
+ attr_reader :errors, :status_code
21
+
22
+ def initialize(message, errors:, status_code:)
23
+ @errors = errors
24
+ @status_code = status_code
25
+ super(message)
26
+ end
27
+ end
28
+
29
+ ADAPTER_KEY = :pdfmonkey_adapter
30
+ private_constant :ADAPTER_KEY
31
+
32
+ def self.current_adapter
33
+ Thread.current[ADAPTER_KEY]
34
+ end
35
+
36
+ def self.with_adapter(adapter)
37
+ previous = Thread.current[ADAPTER_KEY]
38
+ Thread.current[ADAPTER_KEY] = adapter
39
+ yield
40
+ ensure
41
+ Thread.current[ADAPTER_KEY] = previous
42
+ end
11
43
  end
44
+
45
+ require 'pdfmonkey/adapter'
46
+ require 'pdfmonkey/collection'
47
+ require 'pdfmonkey/resource'
48
+ require 'pdfmonkey/current_user'
49
+ require 'pdfmonkey/document'
50
+ require 'pdfmonkey/document_card'
51
+ require 'pdfmonkey/engine'
52
+ require 'pdfmonkey/snippet'
53
+ require 'pdfmonkey/template'
54
+ require 'pdfmonkey/template_card'
55
+ require 'pdfmonkey/template_folder'
56
+ require 'pdfmonkey/webhook'
57
+ require 'pdfmonkey/workspace'
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pdfmonkey
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Courtois
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-01-23 00:00:00.000000000 Z
11
+ date: 2026-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: ostruct
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 0.6.0
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: 0.6.0
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: bundler
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +58,14 @@ dependencies:
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: '1.26'
61
+ version: '1.68'
76
62
  type: :development
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: '1.26'
68
+ version: '1.68'
83
69
  description: Generate awesome PDF with web technologies at pdfmonkey.io
84
70
  email:
85
71
  - scourtois_github@cubyx.fr
@@ -87,30 +73,32 @@ executables: []
87
73
  extensions: []
88
74
  extra_rdoc_files: []
89
75
  files:
90
- - ".github/dependabot.yml"
91
- - ".github/workflows/ci.yml"
92
- - ".gitignore"
93
- - ".rspec"
94
- - ".rubocop.yml"
95
76
  - CHANGELOG.md
96
- - CODE_OF_CONDUCT.md
97
- - Gemfile
98
- - Gemfile.lock
99
77
  - LICENSE.txt
100
78
  - README.md
101
- - Rakefile
102
- - bin/console
103
- - bin/setup
104
79
  - lib/pdfmonkey.rb
105
80
  - lib/pdfmonkey/adapter.rb
81
+ - lib/pdfmonkey/collection.rb
106
82
  - lib/pdfmonkey/configuration.rb
83
+ - lib/pdfmonkey/current_user.rb
107
84
  - lib/pdfmonkey/document.rb
85
+ - lib/pdfmonkey/document_card.rb
86
+ - lib/pdfmonkey/engine.rb
87
+ - lib/pdfmonkey/resource.rb
88
+ - lib/pdfmonkey/snippet.rb
89
+ - lib/pdfmonkey/template.rb
90
+ - lib/pdfmonkey/template_card.rb
91
+ - lib/pdfmonkey/template_folder.rb
108
92
  - lib/pdfmonkey/version.rb
109
- - pdfmonkey.gemspec
93
+ - lib/pdfmonkey/webhook.rb
94
+ - lib/pdfmonkey/workspace.rb
110
95
  homepage: https://github.com/pdfmonkeyio/pdfmonkey-ruby
111
96
  licenses:
112
97
  - MIT
113
- metadata: {}
98
+ metadata:
99
+ changelog_uri: https://github.com/pdfmonkeyio/pdfmonkey-ruby/blob/master/CHANGELOG.md
100
+ source_code_uri: https://github.com/pdfmonkeyio/pdfmonkey-ruby
101
+ rubygems_mfa_required: 'true'
114
102
  post_install_message:
115
103
  rdoc_options: []
116
104
  require_paths:
@@ -119,7 +107,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
119
107
  requirements:
120
108
  - - ">="
121
109
  - !ruby/object:Gem::Version
122
- version: '0'
110
+ version: '3.2'
123
111
  required_rubygems_version: !ruby/object:Gem::Requirement
124
112
  requirements:
125
113
  - - ">="
@@ -1,20 +0,0 @@
1
- version: 2
2
-
3
- updates:
4
- - package-ecosystem: bundler
5
- directory: /
6
- open-pull-requests-limit: 10
7
- schedule:
8
- interval: weekly
9
- day: monday
10
- time: '00:00'
11
- target-branch: master
12
- versioning-strategy: increase-if-necessary
13
-
14
- - package-ecosystem: github-actions
15
- directory: /
16
- schedule:
17
- interval: weekly
18
- day: monday
19
- time: '00:00'
20
- target-branch: master
@@ -1,43 +0,0 @@
1
- name: CI
2
-
3
- on: [push, pull_request]
4
-
5
- jobs:
6
- specs:
7
- name: Run specs with Ruby ${{matrix.ruby}}
8
- runs-on: ubuntu-latest
9
- strategy:
10
- fail-fast: false
11
- matrix:
12
- include:
13
- - ruby: '2.6'
14
- bundler: 2.2.30
15
- - ruby: '2.7'
16
- bundler: 2.2.30
17
- - ruby: '3.0'
18
- bundler: 2.2.30
19
- - ruby: '3.1'
20
- bundler: 2.6.3
21
- - ruby: '3.2'
22
- bundler: 2.6.3
23
- - ruby: '3.3'
24
- bundler: 2.6.3
25
- - ruby: '3.4'
26
- bundler: 2.6.3
27
- - ruby: head
28
- bundler: 2.6.3
29
- experimental: true
30
- steps:
31
- - uses: actions/checkout@v4
32
-
33
- - uses: ruby/setup-ruby@v1
34
- with:
35
- ruby-version: ${{matrix.ruby}}
36
- bundler: ${{matrix.bundler}}
37
- bundler-cache: true
38
-
39
- - name: Install gems
40
- run: bundle _${{matrix.bundler}}_ install
41
-
42
- - name: Run specs
43
- run: bundle _${{matrix.bundler}}_ exec rspec
data/.gitignore DELETED
@@ -1,8 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --color
2
- --require spec_helper