bidi2pdf-rails 0.0.1.pre.alpha → 0.1.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.idea/bidi2pdf-rails.iml +55 -9
  3. data/.rubocop.yml +14 -0
  4. data/CHANGELOG.md +33 -0
  5. data/README.md +117 -27
  6. data/Rakefile +2 -0
  7. data/cliff.toml +126 -0
  8. data/lib/bidi2pdf_rails/browser_console_log_subscriber.rb +24 -0
  9. data/lib/bidi2pdf_rails/chromedriver_manager_singleton.rb +11 -11
  10. data/lib/bidi2pdf_rails/config.rb +133 -0
  11. data/lib/bidi2pdf_rails/configurable.rb +106 -0
  12. data/lib/bidi2pdf_rails/main_log_subscriber.rb +33 -0
  13. data/lib/bidi2pdf_rails/network_log_subscriber.rb +20 -0
  14. data/lib/bidi2pdf_rails/railtie.rb +12 -45
  15. data/lib/bidi2pdf_rails/services/html_renderer.rb +33 -0
  16. data/lib/bidi2pdf_rails/services/html_to_pdf_converter.rb +28 -0
  17. data/lib/bidi2pdf_rails/services/pdf_browser_session.rb +39 -0
  18. data/lib/bidi2pdf_rails/services/pdf_renderer.rb +82 -0
  19. data/lib/bidi2pdf_rails/services/url_to_pdf_converter.rb +82 -0
  20. data/lib/bidi2pdf_rails/version.rb +1 -1
  21. data/lib/bidi2pdf_rails.rb +41 -58
  22. data/lib/generators/bidi2pdf_rails/USAGE +12 -4
  23. data/lib/generators/bidi2pdf_rails/initializer_generator.rb +136 -30
  24. data/lib/generators/bidi2pdf_rails/templates/bidi2pdf_rails.rb.tt +25 -79
  25. data/spec/acceptance/user_can_download_report_pdf_spec.rb +133 -0
  26. data/spec/acceptance/user_can_generate_pdf_from_protected_remote_url_spec.rb +173 -0
  27. data/spec/dummy/app/controllers/reports_controller.rb +37 -0
  28. data/spec/dummy/app/controllers/secure_controller.rb +52 -0
  29. data/spec/dummy/app/views/layouts/simple.html.erb +17 -0
  30. data/spec/dummy/app/views/secure/show.html.erb +10 -0
  31. data/spec/dummy/config/environments/production.rb +1 -1
  32. data/spec/dummy/config/initializers/bidi2pdf_rails.rb +68 -54
  33. data/spec/dummy/config/initializers/cors.rb +1 -1
  34. data/spec/dummy/config/routes.rb +10 -0
  35. data/spec/dummy/log/development.log +16567 -156
  36. data/spec/dummy/log/test.log +53046 -0
  37. data/spec/dummy/tmp/pids/server.pid +1 -1
  38. data/spec/integration/generators/bidi2pdf_rails/initializer_generator_spec.rb +64 -0
  39. data/spec/rails_helper.rb +8 -1
  40. data/spec/spec_helper.rb +47 -5
  41. data/spec/support/default_dirs_helper.rb +32 -0
  42. data/spec/support/pdf_helper.rb +12 -0
  43. data/spec/support/render_setting_helpers.rb +28 -0
  44. data/spec/support/request_server_bootstrap.rb +44 -0
  45. data/spec/{bidi2pdf_rails → unit/bidi2pdf_rails}/bidi2pdf_rails_spec.rb +1 -1
  46. data/spec/unit/bidi2pdf_rails/configurable/base_nested_config_spec.rb +133 -0
  47. data/tasks/changelog.rake +29 -0
  48. data/tasks/coverage.rake +23 -0
  49. metadata +95 -25
  50. data/lib/bidi2pdf_rails/log_subscriber.rb +0 -13
  51. data/spec/dummy/spec/helpers/reports_helper_spec.rb +0 -15
  52. data/spec/dummy/spec/requests/reports_spec.rb +0 -10
  53. data/spec/dummy/spec/views/reports/show.html.erb_spec.rb +0 -5
  54. data/spec/generator/bidie2pdf_rails_initializer_generator_spec.rb +0 -5
  55. data/spec/generator/initializer_generator_spec.rb +0 -5
  56. data/spec/requests/reports_spec.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7316e5fbdad14a0d1e622e7ee89955f20657cdbfced7f79e2c1b2861a9d93c1e
4
- data.tar.gz: c889dae22e63576bdc3bd9cd7e9bae199bb6da39b92819fc817d3811453be663
3
+ metadata.gz: 9d0aa5d0b7d83ed5324b0a8669672f08d7a3e7b22dc7f9d51994f59e4d503df5
4
+ data.tar.gz: 928af8b8e8646b13c027cf2fb88ca216f53d37abc808c325733e18ee1011e1b8
5
5
  SHA512:
6
- metadata.gz: c740e93dfcf86b054f7d1ecc2e503f2d676c02748c8c9bd1cc8dc38fba927b8ad9710407504875f2d610c2e1494b6e5200e940310fc6a338c2bea9e4d4029eb7
7
- data.tar.gz: 8283d5241822de3278fa9916c6be0b6842621368c1695ad3139cef86a8c6cc40c8e65d21a9eacb30805bcef99a87b72a6faa45d308ccb08682f793cf9ecb5490
6
+ metadata.gz: 01abea76bf14ed10a93abe22394621df080e864024ad828de8a7edcf36eed62b12f008e02db06cf6e0b2449408132467df90415918473eabb55bbeb1ca6c91f8
7
+ data.tar.gz: 0b99cbcb01e48f2577e0da652b5a20f6720bbd11feb6e0dc06bea684e4d5c40e8d94b4c72c83862e498ade59050c1ef72bb28902f1f334c0f250821854391fd3
@@ -102,6 +102,7 @@
102
102
  </excluded>
103
103
  </library>
104
104
  </orderEntry>
105
+ <orderEntry type="library" scope="PROVIDED" name="Ascii85 (v2.0.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
105
106
  <orderEntry type="library" scope="PROVIDED" name="actioncable (v7.2.2.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
106
107
  <orderEntry type="library" scope="PROVIDED" name="actionmailbox (v7.2.2.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
107
108
  <orderEntry type="library" scope="PROVIDED" name="actionmailer (v7.2.2.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
@@ -113,6 +114,8 @@
113
114
  <orderEntry type="library" scope="PROVIDED" name="activerecord (v7.2.2.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
114
115
  <orderEntry type="library" scope="PROVIDED" name="activestorage (v7.2.2.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
115
116
  <orderEntry type="library" scope="PROVIDED" name="activesupport (v7.2.2.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
117
+ <orderEntry type="library" scope="PROVIDED" name="afm (v0.2.2, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
118
+ <orderEntry type="library" scope="PROVIDED" name="ammeter (v1.1.7, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
116
119
  <orderEntry type="library" scope="PROVIDED" name="ast (v2.4.3, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
117
120
  <orderEntry type="library" scope="PROVIDED" name="benchmark (v0.4.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
118
121
  <orderEntry type="library" scope="PROVIDED" name="bigdecimal (v3.1.9, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
@@ -128,8 +131,9 @@
128
131
  <orderEntry type="library" scope="PROVIDED" name="drb (v2.2.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
129
132
  <orderEntry type="library" scope="PROVIDED" name="erubi (v1.13.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
130
133
  <orderEntry type="library" scope="PROVIDED" name="event_emitter (v0.2.6, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
131
- <orderEntry type="library" scope="PROVIDED" name="ffi (v1.17.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
134
+ <orderEntry type="library" scope="PROVIDED" name="ffi (v1.17.2, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
132
135
  <orderEntry type="library" scope="PROVIDED" name="globalid (v1.2.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
136
+ <orderEntry type="library" scope="PROVIDED" name="hashery (v2.1.2, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
133
137
  <orderEntry type="library" scope="PROVIDED" name="i18n (v1.14.7, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
134
138
  <orderEntry type="library" scope="PROVIDED" name="io-console (v0.8.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
135
139
  <orderEntry type="library" scope="PROVIDED" name="irb (v1.15.2, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
@@ -148,8 +152,9 @@
148
152
  <orderEntry type="library" scope="PROVIDED" name="net-smtp (v0.5.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
149
153
  <orderEntry type="library" scope="PROVIDED" name="nio4r (v2.7.4, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
150
154
  <orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.18.7, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
151
- <orderEntry type="library" scope="PROVIDED" name="parallel (v1.26.3, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
155
+ <orderEntry type="library" scope="PROVIDED" name="parallel (v1.27.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
152
156
  <orderEntry type="library" scope="PROVIDED" name="parser (v3.3.8.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
157
+ <orderEntry type="library" scope="PROVIDED" name="pdf-reader (v2.14.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
153
158
  <orderEntry type="library" scope="PROVIDED" name="pp (v0.6.2, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
154
159
  <orderEntry type="library" scope="PROVIDED" name="prism (v1.4.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
155
160
  <orderEntry type="library" scope="PROVIDED" name="propshaft (v1.1.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
@@ -181,8 +186,9 @@
181
186
  <orderEntry type="library" scope="PROVIDED" name="rubocop-rails (v2.31.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
182
187
  <orderEntry type="library" scope="PROVIDED" name="rubocop-rails-omakase (v1.1.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
183
188
  <orderEntry type="library" scope="PROVIDED" name="rubocop-rake (v0.7.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
184
- <orderEntry type="library" scope="PROVIDED" name="rubocop-rspec (v3.5.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
189
+ <orderEntry type="library" scope="PROVIDED" name="rubocop-rspec (v3.6.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
185
190
  <orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.13.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
191
+ <orderEntry type="library" scope="PROVIDED" name="ruby-rc4 (v0.1.5, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
186
192
  <orderEntry type="library" scope="PROVIDED" name="rubyzip (v2.4.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
187
193
  <orderEntry type="library" scope="PROVIDED" name="securerandom (v0.4.1, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
188
194
  <orderEntry type="library" scope="PROVIDED" name="simplecov (v0.22.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
@@ -192,14 +198,17 @@
192
198
  <orderEntry type="library" scope="PROVIDED" name="sys-proctable (v1.3.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
193
199
  <orderEntry type="library" scope="PROVIDED" name="thor (v1.3.2, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
194
200
  <orderEntry type="library" scope="PROVIDED" name="timeout (v0.4.3, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
201
+ <orderEntry type="library" scope="PROVIDED" name="ttfunk (v1.8.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
195
202
  <orderEntry type="library" scope="PROVIDED" name="tzinfo (v2.0.6, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
196
203
  <orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v3.1.4, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
197
204
  <orderEntry type="library" scope="PROVIDED" name="unicode-emoji (v4.0.4, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
205
+ <orderEntry type="library" scope="PROVIDED" name="unicode_utils (v1.4.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
198
206
  <orderEntry type="library" scope="PROVIDED" name="useragent (v0.16.11, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
199
207
  <orderEntry type="library" scope="PROVIDED" name="websocket (v1.2.11, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
200
208
  <orderEntry type="library" scope="PROVIDED" name="websocket-client-simple (v0.9.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
201
209
  <orderEntry type="library" scope="PROVIDED" name="websocket-driver (v0.7.7, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
202
210
  <orderEntry type="library" scope="PROVIDED" name="websocket-extensions (v0.1.5, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
211
+ <orderEntry type="library" scope="PROVIDED" name="websocket-native (v1.0.0, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
203
212
  <orderEntry type="library" scope="PROVIDED" name="zeitwerk (v2.7.2, RVM: ruby-3.3.4 [bidi2pdf-rails]) [gem]" level="application" />
204
213
  </component>
205
214
  <component name="RailsGeneratorsCache">
@@ -338,9 +347,6 @@
338
347
  <entry key="config">
339
348
  <value>file://$MODULE_DIR$/config</value>
340
349
  </entry>
341
- <entry key="config/cable">
342
- <value>file://$MODULE_DIR$/config/cable.yml</value>
343
- </entry>
344
350
  <entry key="config/database">
345
351
  <value>file://$MODULE_DIR$/config/database.yml</value>
346
352
  </entry>
@@ -362,9 +368,6 @@
362
368
  <entry key="config/routes.rb">
363
369
  <value>file://$MODULE_DIR$/config/routes.rb</value>
364
370
  </entry>
365
- <entry key="config/secrets">
366
- <value>file://$MODULE_DIR$/config</value>
367
- </entry>
368
371
  <entry key="db">
369
372
  <value>file://$MODULE_DIR$/db</value>
370
373
  </entry>
@@ -398,6 +401,9 @@
398
401
  <entry key="public/stylesheets">
399
402
  <value>file://$MODULE_DIR$/public/stylesheets</value>
400
403
  </entry>
404
+ <entry key="test/mailers/previews">
405
+ <value>file://$MODULE_DIR$/test/mailers/previews</value>
406
+ </entry>
401
407
  <entry key="tmp">
402
408
  <value>file://$MODULE_DIR$/tmp</value>
403
409
  </entry>
@@ -408,4 +414,44 @@
408
414
  <value>file://$MODULE_DIR$/vendor/assets</value>
409
415
  </entry>
410
416
  </component>
417
+ <component name="RakeTasksCache-v2">
418
+ <option name="myRootTask">
419
+ <RakeTaskImpl id="rake">
420
+ <subtasks>
421
+ <RakeTaskImpl description="Build bidi2pdf-rails-0.0.1.alpha.1.gem into the pkg directory" fullCommand="build" id="build" />
422
+ <RakeTaskImpl id="build">
423
+ <subtasks>
424
+ <RakeTaskImpl description="Generate SHA512 checksum of bidi2pdf-rails-0.0.1.alpha.1.gem into the checksums directory" fullCommand="build:checksum" id="checksum" />
425
+ </subtasks>
426
+ </RakeTaskImpl>
427
+ <RakeTaskImpl description="Remove any temporary products" fullCommand="clean" id="clean" />
428
+ <RakeTaskImpl description="Remove any generated files" fullCommand="clobber" id="clobber" />
429
+ <RakeTaskImpl description="Build and install bidi2pdf-rails-0.0.1.alpha.1.gem into system gems" fullCommand="install" id="install" />
430
+ <RakeTaskImpl id="install">
431
+ <subtasks>
432
+ <RakeTaskImpl description="Build and install bidi2pdf-rails-0.0.1.alpha.1.gem into system gems without network access" fullCommand="install:local" id="local" />
433
+ </subtasks>
434
+ </RakeTaskImpl>
435
+ <RakeTaskImpl description="Create tag v0.0.1.alpha.1 and build and push bidi2pdf-rails-0.0.1.alpha.1.gem to https://rubygems.org" fullCommand="release[remote]" id="release[remote]" />
436
+ <RakeTaskImpl description="Run RuboCop" fullCommand="rubocop" id="rubocop" />
437
+ <RakeTaskImpl id="rubocop">
438
+ <subtasks>
439
+ <RakeTaskImpl description="Autocorrect RuboCop offenses (only when it's safe)" fullCommand="rubocop:autocorrect" id="autocorrect" />
440
+ <RakeTaskImpl description="Autocorrect RuboCop offenses (safe and unsafe)" fullCommand="rubocop:autocorrect_all" id="autocorrect_all" />
441
+ <RakeTaskImpl description="" fullCommand="rubocop:auto_correct" id="auto_correct" />
442
+ </subtasks>
443
+ </RakeTaskImpl>
444
+ <RakeTaskImpl description="Run RSpec code examples" fullCommand="spec" id="spec" />
445
+ <RakeTaskImpl description="" fullCommand="release" id="release" />
446
+ <RakeTaskImpl id="release">
447
+ <subtasks>
448
+ <RakeTaskImpl description="" fullCommand="release:guard_clean" id="guard_clean" />
449
+ <RakeTaskImpl description="" fullCommand="release:rubygem_push" id="rubygem_push" />
450
+ <RakeTaskImpl description="" fullCommand="release:source_control_push" id="source_control_push" />
451
+ </subtasks>
452
+ </RakeTaskImpl>
453
+ </subtasks>
454
+ </RakeTaskImpl>
455
+ </option>
456
+ </component>
411
457
  </module>
data/.rubocop.yml CHANGED
@@ -50,9 +50,18 @@ Layout/BeginEndAlignment:
50
50
  Layout/ArrayAlignment:
51
51
  Enabled: false
52
52
 
53
+ Layout/ElseAlignment:
54
+ Enabled: false
55
+
56
+ Layout/EndAlignment:
57
+ Enabled: false
58
+
53
59
  Layout/LineLength:
54
60
  Enabled: false
55
61
 
62
+ Layout/SpaceInsideArrayLiteralBrackets:
63
+ EnforcedStyle: no_space
64
+
56
65
  RSpec/MultipleMemoizedHelpers:
57
66
  Max: 10
58
67
 
@@ -85,6 +94,11 @@ RSpec/DescribeClass:
85
94
  Exclude:
86
95
  - 'spec/acceptance/**/*_spec.rb'
87
96
 
97
+ RSpec/MultipleExpectations:
98
+ Enabled: true
99
+ Exclude:
100
+ - 'spec/acceptance/**/*_spec.rb'
101
+
88
102
  plugins:
89
103
  - rubocop-rake
90
104
  - rubocop-rspec
data/CHANGELOG.md ADDED
@@ -0,0 +1,33 @@
1
+ <!-- generated by git-cliff start -->
2
+
3
+ # Changelog
4
+
5
+ All notable changes to this project will be documented in this file.
6
+
7
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
8
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
9
+
10
+ <!-- generated by git-cliff end -->
11
+
12
+ ## [0.1.0] - 2025-04-21
13
+
14
+ ### 🐛 Fixed
15
+
16
+ - Add PDF rendering from protected remote URLs by @dieter-medium
17
+ - Add acceptance tests for PDF generation with bidi2pdf-rails by @dieter-medium
18
+ - Allow forcing chromedriver manager initialization by @dieter-medium
19
+ - Add unit tests for BaseNestedConfig behavior by @dieter-medium
20
+
21
+ ### 📝 Docs
22
+
23
+ - Enhance README with usage and config examples by @dieter-medium
24
+ - Add CORS configuration details for asset access by @dieter-medium
25
+
26
+ ### 🚀 Added
27
+
28
+ - Enhance configuration and logging for Bidi2pdfRails by @dieter-medium
29
+ - Ensure custom HTML can be used in PDF rendering by @dieter-medium
30
+
31
+ [unreleased](https://github.com/dieter-medium/bidi2pdf-rails/compare/v0.1.0..HEAD)
32
+ [0.1.0](https://github.com/dieter-medium/bidi2pdf-rails/compare/v0.0.1.alpha.1..v0.1.0)
33
+
data/README.md CHANGED
@@ -1,75 +1,165 @@
1
1
  [![Build Status](https://github.com/dieter-medium/bidi2pdf-rails/actions/workflows/ruby.yml/badge.svg)](https://github.com/dieter-medium/bidi2pdf-rails/blob/main/.github/workflows/ruby.yml)
2
2
  [![Maintainability](https://api.codeclimate.com/v1/badges/6425d9893aa3a9ca243e/maintainability)](https://codeclimate.com/github/dieter-medium/bidi2pdf-rails/maintainability)
3
- [![Gem Version](https://badge.fury.io/rb/bidi2pdf-rails.svg)](https://badge.fury.io/rb/bidi2pdf-rails)
4
3
  [![Test Coverage](https://api.codeclimate.com/v1/badges/6425d9893aa3a9ca243e/test_coverage)](https://codeclimate.com/github/dieter-medium/bidi2pdf-rails/test_coverage)
4
+ [![Gem Version](https://badge.fury.io/rb/bidi2pdf-rails.svg)](https://badge.fury.io/rb/bidi2pdf-rails)
5
5
  [![Open Source Helpers](https://www.codetriage.com/dieter-medium/bidi2pdf-rails/badges/users.svg)](https://www.codetriage.com/dieter-medium/bidi2pdf-rails)
6
6
 
7
-
8
7
  # 📄 Bidi2pdfRails
9
8
 
10
- **Bidi2pdfRails** is the official Rails integration for [Bidi2pdf](https://github.com/dieter-medium/bidi2pdf) a modern, browser-based solution for converting HTML to high-quality PDFs.
11
- It leverages headless browsing and offers a simple, flexible interface for PDF generation directly from your Rails application.
9
+ **Bidi2pdfRails** is the official Rails integration for [Bidi2pdf](https://github.com/dieter-medium/bidi2pdf) a
10
+ modern, headless-browser-based PDF rendering engine.
11
+ Generate high-fidelity PDFs directly from your Rails views or external URLs with minimal setup.
12
12
 
13
- > **⚠️ Note:** This project is currently **under development** and **not yet recommended for production use**.
13
+ > ⚠️ **Project status:** _Under active development_. Not yet recommended for production use.
14
14
 
15
15
  ---
16
16
 
17
- ## 🚀 Why Bidi2pdfRails?
17
+ ## Features
18
18
 
19
- - Utilizes modern browser technologies for accurate rendering (similar to `grover` or `wicked_pdf`)
20
- - Easy to integrate into existing Rails projects
21
- - Configurable options: URL, output path, rendering settings
19
+ - 🔍 Accurate PDF rendering using a real browser engine
20
+ - 💾 Supports both HTML string rendering and remote URL conversion
21
+ - 🔐 Built-in support for authentication (Basic Auth, cookies, headers)
22
+ - 🧰 Full test suite with examples for Rails controller integration
23
+ - 🧠 Sensible defaults, yet fully configurable
22
24
 
23
25
  ---
24
26
 
25
27
  ## 🔧 Installation
26
28
 
27
- Add the following lines to your `Gemfile`:
29
+ Add to your Gemfile:
28
30
 
29
31
  ```ruby
30
- gem "bidi2pdf-rails"
31
- # As long as the gem is not published, use:
32
- gem "bidi2pdf-rails", github: "dieter-medium/bidi2pdf", branch: "main"
32
+ # Until released, use the GitHub repo
33
+ gem "bidi2pdf-rails", github: "dieter-medium/bidi2pdf-rails", branch: "main"
33
34
  gem "bidi2pdf", github: "dieter-medium/bidi2pdf", branch: "main"
35
+
36
+ # Optional for performance:
37
+ # gem "websocket-native"
34
38
  ```
35
39
 
36
- Then install the dependencies:
40
+ Install it:
37
41
 
38
42
  ```bash
39
- bundle
43
+ bundle install
40
44
  ```
41
45
 
42
- Generate the initializer:
46
+ Generate the config initializer:
43
47
 
44
48
  ```bash
45
49
  bin/rails generate bidi2pdf_rails:initializer
46
50
  ```
47
51
 
48
- Alternatively, install it manually:
52
+ ---
49
53
 
50
- ```bash
51
- gem install bidi2pdf-rails
54
+ ## 📦 Usage Examples
55
+
56
+ ### 📄 Rendering a Rails View as PDF
57
+
58
+ ```ruby
59
+ # app/controllers/invoices_controller.rb
60
+
61
+ def show
62
+ render pdf: "invoice",
63
+ template: "invoices/show",
64
+ layout: "pdf",
65
+ locals: { invoice: @invoice },
66
+ print_options: { landscape: true },
67
+ wait_for_network_idle: true
68
+ end
69
+ ```
70
+
71
+ ### 🌐 Rendering a Remote URL to PDF
72
+
73
+ ```ruby
74
+
75
+ def convert
76
+ render pdf: "external-report",
77
+ url: "https://example.com/dashboard",
78
+ wait_for_page_loaded: false,
79
+ print_options: { page: { format: :A4 } }
80
+ end
52
81
  ```
53
82
 
54
83
  ---
55
84
 
56
- ## 🧪 Example & Getting Started
85
+ ## 🛡️ Authentication Support
86
+
87
+ Need to convert pages that require authentication? No problem. Use:
88
+
89
+ - `auth: { username:, password: }`
90
+ - `cookies: { session_key: value }`
91
+ - `headers: { "Authorization" => "Bearer ..." }`
92
+
93
+ Example:
94
+
95
+ ```ruby
96
+ render pdf: "secure",
97
+ url: secure_report_url,
98
+ auth: { username: "admin", password: "secret" }
99
+ ```
100
+
101
+ Or use global config in `bidi2pdf_rails.rb` initializer:
102
+
103
+ ```ruby
104
+ config.render_remote_settings.basic_auth_user = ->(_) { "admin" }
105
+ config.render_remote_settings.basic_auth_pass = ->(_) { Rails.application.credentials.dig(:pdf, :auth_pass) }
106
+ ```
107
+
108
+ ---
109
+
110
+ ## 📂 Asset Access via CORS
111
+
112
+ When rendering HTML with `render_to_string`, Chromium needs access to your assets (CSS, images, fonts).
113
+ Enable CORS for `/assets` using `rack-cors`:
114
+
115
+ ```ruby
116
+ # Gemfile
117
+ gem 'rack-cors'
118
+
119
+ # config/initializers/cors.rb
120
+ Rails.application.config.middleware.insert_before 0, Rack::Cors do
121
+ allow do
122
+ origins '*'
123
+ resource '/assets/*', headers: :any, methods: [:get, :options]
124
+ end
125
+ end
126
+ ```
127
+
128
+ ---
129
+
130
+ ## 🧪 Acceptance Examples
131
+
132
+ This repo includes **real integration tests** that serve as usage documentation:
133
+
134
+ - [Download PDF with `.pdf` format](spec/acceptance/user_can_download_report_pdf_spec.rb)
135
+ - [Render protected remote URLs using Basic Auth, cookies, and headers](spec/acceptance/user_can_generate_pdf_from_protected_remote_url_spec.rb)
136
+
137
+ ---
138
+
139
+ ## 🧠 Configuration
140
+
141
+ Bidi2pdfRails is highly configurable.
142
+
143
+ See full config options in:
144
+
145
+ ```bash
146
+ bin/rails generate bidi2pdf_rails:initializer
147
+ ```
57
148
 
58
- You can find a full example inside the [`spec/dummy`](spec/dummy) directory of this repository.
59
- This demonstrates how to use `Bidi2pdfRails` in a realistic mini Rails application setup.
149
+ Or explore `Bidi2pdfRails::Configuration` in the source.
60
150
 
61
151
  ---
62
152
 
63
153
  ## 🙌 Contributing
64
154
 
65
- Want to contribute?
66
- Pull requests, bug reports, and ideas are warmly welcome!
155
+ Pull requests, issues, and ideas are all welcome 🙏
156
+ Want to contribute? Just fork, branch, and PR like a boss.
67
157
 
68
- *Contribution guidelines will be added soon.*
158
+ > Contribution guide coming soon!
69
159
 
70
160
  ---
71
161
 
72
162
  ## 📄 License
73
163
 
74
- This gem is open-source and available under the terms of the [MIT License](https://opensource.org/licenses/MIT).
75
- Free to use with responsibility.
164
+ This gem is released under the [MIT License](https://opensource.org/licenses/MIT).
165
+ Use freely and responsibly.
data/Rakefile CHANGED
@@ -9,3 +9,5 @@ RSpec::Core::RakeTask.new(:spec)
9
9
  require "rubocop/rake_task"
10
10
 
11
11
  RuboCop::RakeTask.new
12
+
13
+ Dir.glob("tasks/*.rake").each { |r| load r }
data/cliff.toml ADDED
@@ -0,0 +1,126 @@
1
+ # git-cliff ~ configuration file
2
+ # https://git-cliff.org/docs/configuration
3
+
4
+ [changelog]
5
+ # template for the changelog header
6
+ header = """
7
+ <!-- generated by git-cliff start -->
8
+ # Changelog\n
9
+ All notable changes to this project will be documented in this file.
10
+
11
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
12
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n
13
+ """
14
+ # template for the changelog body
15
+ # https://keats.github.io/tera/docs/#introduction
16
+ body = """
17
+ {%- macro remote_url() -%}
18
+ https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
19
+ {%- endmacro -%}
20
+
21
+ {% if version -%}
22
+ ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
23
+ {% else -%}
24
+ ## [Unreleased]
25
+ {% endif -%}
26
+
27
+ {% for group, commits in commits | group_by(attribute="group") %}
28
+ ### {{ group | upper_first }}
29
+ {%- for commit in commits %}
30
+ - {{ commit.message | split(pat="\n") | first | upper_first | trim }}\
31
+ {% if commit.remote.username %} by @{{ commit.remote.username }}{%- endif -%}
32
+ {% if commit.remote.pr_number %} in \
33
+ [#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }}) \
34
+ {%- endif -%}
35
+ {% endfor %}
36
+ {% endfor %}
37
+
38
+ {%- if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
39
+ ## New Contributors
40
+ {%- endif -%}
41
+
42
+ {% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
43
+ * @{{ contributor.username }} made their first contribution
44
+ {%- if contributor.pr_number %} in \
45
+ [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
46
+ {%- endif %}
47
+ {%- endfor %}\n
48
+ """
49
+ # template for the changelog footer
50
+ footer = """
51
+ {%- macro remote_url() -%}
52
+ https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
53
+ {%- endmacro -%}
54
+
55
+ {% for release in releases -%}
56
+ {% if release.version -%}
57
+ {% if release.previous.version -%}
58
+ [{{ release.version | trim_start_matches(pat="v") }}]: \
59
+ {{ self::remote_url() }}/compare/{{ release.previous.version }}..{{ release.version }}
60
+ {% endif -%}
61
+ {% else -%}
62
+ [unreleased]: {{ self::remote_url() }}/compare/{{ release.previous.version }}..HEAD
63
+ {% endif -%}
64
+ {% endfor %}
65
+ <!-- generated by git-cliff end -->
66
+ """
67
+ # remove the leading and trailing whitespace from the templates
68
+ trim = true
69
+
70
+ [git]
71
+ # parse the commits based on https://www.conventionalcommits.org
72
+ conventional_commits = true
73
+ # filter out the commits that are not conventional
74
+ filter_unconventional = false
75
+ # regex for preprocessing the commit messages
76
+ commit_preprocessors = [
77
+ # remove issue numbers from commits
78
+ { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "" },
79
+ ]
80
+ # regex for parsing and grouping commits
81
+ commit_parsers = [
82
+ # ✅ Features (additions)
83
+ { message = "^feat(?:\\([^)]+\\))?!?:", group = "🚀 Added" },
84
+ { message = "^[aA]dd", group = "🚀 Added" },
85
+ { message = "^[sS]upport", group = "🚀 Added" },
86
+ # ❌ Removals
87
+ { message = "^[rR]emove", group = "🗑️ Removed" },
88
+ { message = "^[dD]elete", group = "🗑️ Removed" },
89
+ # 🐛 Fixes
90
+ { message = "^fix(?:\\([^)]+\\))?!?:", group = "🐛 Fixed" },
91
+ { message = "^[tT]est", group = "🐛 Fixed" },
92
+ { message = "^[fF]ix", group = "🐛 Fixed" },
93
+ # 🎨 Refactors
94
+ { message = "^refactor(?:\\([^)]+\\))?!?:", group = "🎨 Refactored" },
95
+ # ⚡️ Performance
96
+ { message = "^perf(?:\\([^)]+\\))?!?:", group = "⚡️ Performance" },
97
+ # 📝 Docs
98
+ { message = "^docs(?:\\([^)]+\\))?!?:", group = "📝 Docs" },
99
+ # 💄 Style (formatting, whitespace, etc.)
100
+ { message = "^style(?:\\([^)]+\\))?!?:", group = "💄 Style" },
101
+ # 🧪 Tests
102
+ { message = "^test(?:\\([^)]+\\))?!?:", group = "🧪 Tests" },
103
+ # 🔧 Build
104
+ { message = "^build(?:\\([^)]+\\))?!?:", group = "🔧 Build" },
105
+ # 🛠️ CI
106
+ { message = "^ci(?:\\([^)]+\\))?!?:", skip = true },
107
+ # 🧹 Chores (skip)
108
+ { message = "^chore\\(release\\): prepare for", skip = true },
109
+ { message = "^chore\\(deps.*\\)", skip = true },
110
+ { message = "^chore\\(pr\\)", skip = true },
111
+ { message = "^chore\\(pull\\)", skip = true },
112
+ { message = "^chore(?:\\([^)]+\\))?!?:", skip = true },
113
+ { message = "^\\s*chore", skip = true },
114
+ # ⏪ Reverts
115
+ { message = "^revert(?:\\([^)]+\\))?!?:", group = "⏪ Reverted" },
116
+ # 🌀 Catch-all (only if nothing else matched)
117
+ { message = "^.*", group = "🔄 Changed" }
118
+ ]
119
+
120
+
121
+ # filter out the commits that are not matched by commit parsers
122
+ filter_commits = false
123
+ # sort the tags topologically
124
+ topo_order = false
125
+ # sort the commits inside sections by oldest/newest order
126
+ sort_commits = "newest"
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bidi2pdf/bidi/browser_console_logger"
4
+
5
+ module Bidi2pdfRails
6
+ class BrowserConsoleLogSubscriber < ActiveSupport::LogSubscriber
7
+ def browser_console_log_received(event)
8
+ payload = event.payload
9
+ timestamp = Bidi2pdf::Bidi::BrowserConsoleLogger.format_timestamp(payload[:timestamp])
10
+
11
+ logger.tagged("bidi2pdf_rails", "browser_console", timestamp) do |tagged_logger|
12
+ verbose_logger = Bidi2pdf::VerboseLogger.new(tagged_logger, Bidi2pdfRails.config.general_options.verbosity_value)
13
+ Bidi2pdf::Bidi::BrowserConsoleLogger.new(verbose_logger)
14
+ .builder
15
+ .with_level(payload[:level])
16
+ .with_prefix("")
17
+ .with_text(payload[:text])
18
+ .with_args(payload[:args])
19
+ .with_stack_trace(payload[:stack_trace])
20
+ .log_event
21
+ end
22
+ end
23
+ end
24
+ end
@@ -5,28 +5,28 @@ module Bidi2pdfRails
5
5
  class << self
6
6
  attr_reader :manager, :session
7
7
 
8
- def initialize_manager
9
- return unless running_as_server?
8
+ def initialize_manager(force: false)
9
+ return unless running_as_server? || force
10
10
 
11
11
  @mutex ||= Mutex.new
12
12
  @mutex.synchronize do
13
13
  return if @manager && @session
14
14
 
15
- msg = Bidi2pdfRails.remote_browser_url ? "Remote session" : "ChromeDriver manager"
15
+ msg = Bidi2pdfRails.use_remote_browser? ? "Remote session" : "ChromeDriver manager"
16
16
 
17
17
  Bidi2pdfRails.logger.info "Initializing Bidi2pdf #{msg}"
18
18
 
19
- if Bidi2pdfRails.remote_browser_url
19
+ if Bidi2pdfRails.use_remote_browser?
20
20
  @session = Bidi::Session.new(
21
- session_url: Bidi2pdfRails.remote_browser_url,
22
- headless: Bidi2pdfRails.headless,
23
- chrome_args: Bidi2pdfRails.chrome_session_args
21
+ session_url: Bidi2pdfRails.config.render_remote_settings.browser_url_value,
22
+ headless: Bidi2pdfRails.config.general_options.headless_value,
23
+ chrome_args: Bidi2pdfRails.config.general_options.chrome_session_args_value
24
24
  )
25
25
  else
26
26
  @manager = Bidi2pdf::ChromedriverManager.new(
27
- port: Bidi2pdfRails.chromedriver_port,
28
- headless: Bidi2pdfRails.headless,
29
- chrome_args: Bidi2pdfRails.chrome_session_args
27
+ port: Bidi2pdfRails.config.chromedriver_settings.port_value,
28
+ headless: Bidi2pdfRails.config.general_options.headless_value,
29
+ chrome_args: Bidi2pdfRails.config.general_options.chrome_session_args_value
30
30
  )
31
31
  @manager.start
32
32
  @session = @manager.session
@@ -42,7 +42,7 @@ module Bidi2pdfRails
42
42
 
43
43
  @mutex ||= Mutex.new
44
44
  @mutex.synchronize do
45
- msg = Bidi2pdfRails.remote_browser_url ? "Remote session" : "ChromeDriver manager"
45
+ msg = Bidi2pdfRails.use_remote_browser? ? "Remote session" : "ChromeDriver manager"
46
46
  Bidi2pdfRails.logger.info "Shutting down Bidi2pdf #{msg}"
47
47
  @session&.close
48
48
  @manager&.stop