bidi2pdf-rails 0.0.1.pre.alpha → 0.1.1
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 +4 -4
- data/.idea/bidi2pdf-rails.iml +68 -84
- data/.rubocop.yml +14 -0
- data/CHANGELOG.md +54 -0
- data/README.md +118 -28
- data/Rakefile +2 -0
- data/cliff.toml +126 -0
- data/lib/bidi2pdf_rails/browser_console_log_subscriber.rb +24 -0
- data/lib/bidi2pdf_rails/chromedriver_manager_singleton.rb +11 -11
- data/lib/bidi2pdf_rails/config.rb +137 -0
- data/lib/bidi2pdf_rails/configurable.rb +106 -0
- data/lib/bidi2pdf_rails/main_log_subscriber.rb +33 -0
- data/lib/bidi2pdf_rails/network_log_subscriber.rb +20 -0
- data/lib/bidi2pdf_rails/railtie.rb +13 -45
- data/lib/bidi2pdf_rails/services/html_renderer.rb +33 -0
- data/lib/bidi2pdf_rails/services/html_to_pdf_converter.rb +37 -0
- data/lib/bidi2pdf_rails/services/pdf_browser_session.rb +38 -0
- data/lib/bidi2pdf_rails/services/pdf_injection.rb +31 -0
- data/lib/bidi2pdf_rails/services/pdf_renderer.rb +94 -0
- data/lib/bidi2pdf_rails/services/url_to_pdf_converter.rb +91 -0
- data/lib/bidi2pdf_rails/version.rb +1 -1
- data/lib/bidi2pdf_rails.rb +41 -58
- data/lib/generators/bidi2pdf_rails/USAGE +12 -4
- data/lib/generators/bidi2pdf_rails/initializer_generator.rb +136 -30
- data/lib/generators/bidi2pdf_rails/templates/bidi2pdf_rails.rb.tt +25 -79
- data/spec/acceptance/user_can_download_report_pdf_spec.rb +133 -0
- data/spec/acceptance/user_can_generate_pdf_from_protected_remote_url_spec.rb +173 -0
- data/spec/acceptance/user_can_inject_css_before_pdf_printing_spec.rb +132 -0
- data/spec/acceptance/user_can_inject_js_before_pdf_printing_spec.rb +158 -0
- data/spec/dummy/app/assets/javascripts/simple.js +12 -0
- data/spec/dummy/app/assets/stylesheets/simple.css +3 -0
- data/spec/dummy/app/controllers/reports_controller.rb +47 -0
- data/spec/dummy/app/controllers/secure_controller.rb +52 -0
- data/spec/dummy/app/views/layouts/simple.html.erb +17 -0
- data/spec/dummy/app/views/reports/simple.html.erb +6 -0
- data/spec/dummy/app/views/secure/show.html.erb +10 -0
- data/spec/dummy/config/environments/production.rb +1 -1
- data/spec/dummy/config/initializers/bidi2pdf_rails.rb +72 -54
- data/spec/dummy/config/initializers/cors.rb +1 -1
- data/spec/dummy/config/routes.rb +14 -0
- data/spec/dummy/log/development.log +18331 -158
- data/spec/dummy/log/test.log +87874 -0
- data/spec/dummy/tmp/pids/server.pid +1 -1
- data/spec/integration/generators/bidi2pdf_rails/initializer_generator_spec.rb +64 -0
- data/spec/rails_helper.rb +8 -1
- data/spec/spec_helper.rb +47 -5
- data/spec/support/default_dirs_helper.rb +32 -0
- data/spec/support/pdf_helper.rb +12 -0
- data/spec/support/render_setting_helpers.rb +47 -0
- data/spec/support/request_server_bootstrap.rb +44 -0
- data/spec/{bidi2pdf_rails → unit/bidi2pdf_rails}/bidi2pdf_rails_spec.rb +1 -1
- data/spec/unit/bidi2pdf_rails/configurable/base_nested_config_spec.rb +133 -0
- data/tasks/changelog.rake +29 -0
- data/tasks/coverage.rake +23 -0
- metadata +108 -27
- data/lib/bidi2pdf_rails/log_subscriber.rb +0 -13
- data/spec/dummy/spec/helpers/reports_helper_spec.rb +0 -15
- data/spec/dummy/spec/requests/reports_spec.rb +0 -10
- data/spec/dummy/spec/views/reports/show.html.erb_spec.rb +0 -5
- data/spec/generator/bidie2pdf_rails_initializer_generator_spec.rb +0 -5
- data/spec/generator/initializer_generator_spec.rb +0 -5
- data/spec/requests/reports_spec.rb +0 -17
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bidi2pdfRails
|
4
|
+
module Services
|
5
|
+
module PdfBrowserSession
|
6
|
+
def run_browser_session
|
7
|
+
thread = Thread.new do
|
8
|
+
Rails.application.executor.wrap do
|
9
|
+
browser = ChromedriverManagerSingleton.session.browser
|
10
|
+
context = browser.create_user_context
|
11
|
+
window = context.create_browser_window
|
12
|
+
tab = window.create_browser_tab
|
13
|
+
|
14
|
+
begin
|
15
|
+
prepare_tab(tab)
|
16
|
+
tab.print(print_options: @print_options)
|
17
|
+
ensure
|
18
|
+
tab&.close
|
19
|
+
window&.close
|
20
|
+
context&.close
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
pdf_data = thread.value
|
26
|
+
|
27
|
+
Base64.decode64(pdf_data)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def wait_for_tab(tab)
|
33
|
+
tab.wait_until_network_idle if @wait_for_network_idle
|
34
|
+
tab.wait_until_page_loaded(check_script: @wait_for_page_check_script) if @wait_for_page_loaded
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bidi2pdfRails
|
4
|
+
module Services
|
5
|
+
module PdfInjection
|
6
|
+
def inject_custom_css(tab, custom_css, custom_css_url)
|
7
|
+
return unless custom_css || custom_css_url
|
8
|
+
|
9
|
+
if custom_css
|
10
|
+
tab.inject_style(url: nil, content: custom_css, id: nil)
|
11
|
+
end
|
12
|
+
|
13
|
+
if custom_css_url
|
14
|
+
tab.inject_style(url: custom_css_url, content: nil, id: nil)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def inject_custom_js(tab, custom_js, custom_js_url)
|
19
|
+
return unless custom_js || custom_js_url
|
20
|
+
|
21
|
+
if custom_js
|
22
|
+
tab.inject_script(url: nil, content: custom_js, id: nil)
|
23
|
+
end
|
24
|
+
|
25
|
+
if custom_js_url
|
26
|
+
tab.inject_script(url: custom_js_url, content: nil, id: nil)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bidi2pdfRails
|
4
|
+
module Services
|
5
|
+
# PdfRenderer is responsible for rendering a Rails view into a PDF using headless Chrome.
|
6
|
+
#
|
7
|
+
# It accepts a mix of HTML rendering options (passed to `render_to_string`) and PDF generation options.
|
8
|
+
#
|
9
|
+
# @example Basic usage
|
10
|
+
# renderer = Bidi2pdfRails::Services::PdfRenderer.new("invoice", { template: "invoices/show" }, controller)
|
11
|
+
# renderer.render_pdf
|
12
|
+
#
|
13
|
+
# @param filename [String] the base filename for the generated PDF (used for download naming)
|
14
|
+
# @param options [Hash] rendering options including both HTML and PDF-specific options
|
15
|
+
# @option options [String] :template The template to render (or other render_to_string keys like :partial, :layout, etc.)
|
16
|
+
# @option options [String] :asset_host Optional asset host override
|
17
|
+
# @option options [Hash] :print_options Options passed to the Chrome PDF print API
|
18
|
+
# @option options [Boolean] :wait_for_network_idle Wait for network to go idle before generating PDF (default: config default)
|
19
|
+
# @option options [Boolean] :wait_for_page_loaded Wait for page load event before generating PDF (default: config default)
|
20
|
+
# @option options [String] :wait_for_page_check_script JavaScript condition to wait for before generating PDF
|
21
|
+
#
|
22
|
+
class PdfRenderer
|
23
|
+
PDF_OPTIONS = %i[
|
24
|
+
print_options
|
25
|
+
asset_host
|
26
|
+
wait_for_network_idle
|
27
|
+
wait_for_page_loaded
|
28
|
+
wait_for_page_check_script
|
29
|
+
html
|
30
|
+
].freeze
|
31
|
+
|
32
|
+
PRINT_URL_OPTIONS = %i[
|
33
|
+
url
|
34
|
+
auth
|
35
|
+
headers
|
36
|
+
cookies
|
37
|
+
].freeze
|
38
|
+
|
39
|
+
def initialize(filename, options, controller)
|
40
|
+
@filename = filename
|
41
|
+
@pdf_options = options.slice(*PDF_OPTIONS)
|
42
|
+
@print_url_options = options.slice(*PRINT_URL_OPTIONS)
|
43
|
+
@html_options = options.except(*(PDF_OPTIONS + PRINT_URL_OPTIONS))
|
44
|
+
@controller = controller
|
45
|
+
end
|
46
|
+
|
47
|
+
def render_pdf
|
48
|
+
ActiveSupport::Notifications.instrument("handle_printing.bidi2pdf_rails") do
|
49
|
+
print_options = Bidi2pdfRails.config.pdf_settings_for_bidi_cmd(@pdf_options[:print_options] || {})
|
50
|
+
wait_for_network_idle = @pdf_options.fetch(:wait_for_network_idle, Bidi2pdfRails.config.general_options.wait_for_network_idle_value)
|
51
|
+
wait_for_page_loaded = @pdf_options.fetch(:wait_for_page_loaded, Bidi2pdfRails.config.general_options.wait_for_page_loaded_value)
|
52
|
+
wait_for_page_check_script = @pdf_options.fetch(:wait_for_page_check_script, Bidi2pdfRails.config.general_options.wait_for_page_check_script_value)
|
53
|
+
custom_css = @pdf_options.fetch(:custom_css, Bidi2pdfRails.config.pdf_settings.custom_css_value(@controller))
|
54
|
+
custom_css_url = @pdf_options.fetch(:custom_css_url, Bidi2pdfRails.config.pdf_settings.custom_css_url_value(@controller))
|
55
|
+
custom_js = @pdf_options.fetch(:custom_js, Bidi2pdfRails.config.pdf_settings.custom_js_value(@controller))
|
56
|
+
custom_js_url = @pdf_options.fetch(:custom_js_url, Bidi2pdfRails.config.pdf_settings.custom_js_url_value(@controller))
|
57
|
+
|
58
|
+
if @print_url_options[:url]
|
59
|
+
headers = @print_url_options[:headers] || Bidi2pdfRails.config.render_remote_settings.headers_value(@controller)
|
60
|
+
cookies = @print_url_options[:cookies] || Bidi2pdfRails.config.render_remote_settings.cookies_value(@controller)
|
61
|
+
auth = @print_url_options[:auth] || { username: Bidi2pdfRails.config.render_remote_settings.basic_auth_user_value(@controller), password: Bidi2pdfRails.config.render_remote_settings.basic_auth_pass_value(@controller) }
|
62
|
+
|
63
|
+
UrlToPdfConverter.new(@print_url_options[:url],
|
64
|
+
headers: headers,
|
65
|
+
cookies: cookies,
|
66
|
+
auth: auth,
|
67
|
+
print_options: print_options,
|
68
|
+
wait_for_network_idle: wait_for_network_idle,
|
69
|
+
wait_for_page_loaded: wait_for_page_loaded,
|
70
|
+
wait_for_page_check_script: wait_for_page_check_script,
|
71
|
+
custom_css: custom_css,
|
72
|
+
custom_css_url: custom_css_url,
|
73
|
+
custom_js: custom_js,
|
74
|
+
custom_js_url: custom_js_url,
|
75
|
+
).generate
|
76
|
+
else
|
77
|
+
html = @html_options.fetch(:inline, HtmlRenderer.new(@controller, @html_options).render)
|
78
|
+
|
79
|
+
HtmlToPdfConverter.new(html,
|
80
|
+
print_options: print_options,
|
81
|
+
wait_for_network_idle: wait_for_network_idle,
|
82
|
+
wait_for_page_loaded: wait_for_page_loaded,
|
83
|
+
wait_for_page_check_script: wait_for_page_check_script,
|
84
|
+
custom_css: custom_css,
|
85
|
+
custom_css_url: custom_css_url,
|
86
|
+
custom_js: custom_js,
|
87
|
+
custom_js_url: custom_js_url,
|
88
|
+
).generate
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bidi2pdfRails
|
4
|
+
module Services
|
5
|
+
class UrlToPdfConverter
|
6
|
+
include PdfBrowserSession
|
7
|
+
include PdfInjection
|
8
|
+
|
9
|
+
def initialize(url, headers: {}, cookies: {}, auth: {}, print_options: {}, wait_for_network_idle: true, wait_for_page_loaded: true, wait_for_page_check_script: nil, custom_css: nil, custom_css_url: nil, custom_js: nil, custom_js_url: nil)
|
10
|
+
@url = url
|
11
|
+
@headers = headers || {}
|
12
|
+
@cookies = cookies || {}
|
13
|
+
@auth = auth || {}
|
14
|
+
@print_options = print_options
|
15
|
+
@wait_for_network_idle = wait_for_network_idle
|
16
|
+
@wait_for_page_loaded = wait_for_page_loaded
|
17
|
+
@wait_for_page_check_script = wait_for_page_check_script
|
18
|
+
@custom_css = custom_css
|
19
|
+
@custom_css_url = custom_css_url
|
20
|
+
@custom_js = custom_js
|
21
|
+
@custom_js_url = custom_js_url
|
22
|
+
end
|
23
|
+
|
24
|
+
def generate
|
25
|
+
run_browser_session
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def prepare_tab(tab)
|
31
|
+
add_headers(tab)
|
32
|
+
add_basic_auth(tab)
|
33
|
+
add_cookies(tab)
|
34
|
+
|
35
|
+
tab.navigate_to(@url)
|
36
|
+
|
37
|
+
inject_custom_css(tab, @custom_css, @custom_css_url)
|
38
|
+
inject_custom_js(tab, @custom_js, @custom_js_url)
|
39
|
+
|
40
|
+
wait_for_tab(tab)
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_cookies(tab)
|
44
|
+
@cookies.each do |name, value|
|
45
|
+
tab.set_cookie(
|
46
|
+
name: name,
|
47
|
+
value: value,
|
48
|
+
domain: domain,
|
49
|
+
secure: uri.scheme == "https"
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_headers(tab)
|
55
|
+
@headers.each do |name, value|
|
56
|
+
tab.add_headers(
|
57
|
+
url_patterns: url_patterns,
|
58
|
+
headers: [{ name: name, value: value }]
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_basic_auth(tab)
|
64
|
+
return unless @auth[:username] && @auth[:password]
|
65
|
+
|
66
|
+
tab.basic_auth(
|
67
|
+
url_patterns: url_patterns,
|
68
|
+
username: @auth[:username],
|
69
|
+
password: @auth[:password]
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
def uri
|
74
|
+
@uri ||= URI(@url)
|
75
|
+
end
|
76
|
+
|
77
|
+
def domain
|
78
|
+
uri.host
|
79
|
+
end
|
80
|
+
|
81
|
+
def url_patterns
|
82
|
+
[{
|
83
|
+
type: "pattern",
|
84
|
+
protocol: uri.scheme,
|
85
|
+
hostname: uri.host,
|
86
|
+
port: uri.port.to_s
|
87
|
+
}]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/bidi2pdf_rails.rb
CHANGED
@@ -1,87 +1,70 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "bidi2pdf"
|
4
|
-
require "
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
require "bidi2pdf/bidi/commands/print_parameters_validator"
|
5
|
+
require_relative "bidi2pdf_rails/version"
|
6
|
+
require_relative "bidi2pdf_rails/config"
|
7
|
+
require_relative "bidi2pdf_rails/railtie"
|
8
|
+
require_relative "bidi2pdf_rails/chromedriver_manager_singleton"
|
9
|
+
require_relative "bidi2pdf_rails/main_log_subscriber"
|
10
|
+
require_relative "bidi2pdf_rails/browser_console_log_subscriber"
|
11
|
+
require_relative "bidi2pdf_rails/network_log_subscriber"
|
8
12
|
|
9
13
|
module Bidi2pdfRails
|
10
14
|
class << self
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
:viewport_width, :viewport_height,
|
15
|
-
:pdf_margin_top, :pdf_margin_bottom, :pdf_margin_left, :pdf_margin_right,
|
16
|
-
:pdf_scale, :pdf_print_background, :pdf_format, :pdf_orientation, :verbosity
|
15
|
+
def config
|
16
|
+
Config.instance
|
17
|
+
end
|
17
18
|
|
18
19
|
# Allow configuration through a block
|
19
20
|
def configure
|
20
|
-
yield
|
21
|
+
yield config if block_given?
|
21
22
|
|
22
|
-
|
23
|
-
end
|
23
|
+
config.validate_print_options!
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
Bidi2pdf.configure do |config|
|
28
|
-
config.notification_service = notification_service
|
25
|
+
apply_bidi2pdf_config config
|
26
|
+
end
|
29
27
|
|
30
|
-
|
31
|
-
|
28
|
+
def apply_bidi2pdf_config(config = Config.instance)
|
29
|
+
Bidi2pdf.configure do |bidi2pdf_config|
|
30
|
+
bidi2pdf_config.notification_service = config.general_options.notification_service_value
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
else
|
36
|
-
config.network_events_logger = Logger.new(nil) # Disable network events logging
|
37
|
-
end
|
32
|
+
bidi2pdf_config.logger = config.general_options.logger_value&.tagged("bidi2pdf")
|
33
|
+
bidi2pdf_config.default_timeout = config.general_options.default_timeout_value
|
38
34
|
|
39
|
-
|
40
|
-
|
41
|
-
else
|
42
|
-
config.browser_console_logger = Logger.new(nil) # Disable browser console logging
|
43
|
-
end
|
35
|
+
bidi2pdf_config.network_events_logger = Logger.new(nil)
|
36
|
+
bidi2pdf_config.browser_console_logger = Logger.new(nil)
|
44
37
|
|
45
|
-
|
38
|
+
bidi2pdf_config.enable_default_logging_subscriber = false
|
46
39
|
end
|
47
40
|
|
48
|
-
Chromedriver::Binary.configure do |
|
49
|
-
|
41
|
+
Chromedriver::Binary.configure do |chromedriver_config|
|
42
|
+
chromedriver_config.logger = config.general_options.logger_value&.tagged("bidi2pdf")
|
50
43
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
44
|
+
chromedriver_config.proxy_addr = config.proxy_settings.addr_value
|
45
|
+
chromedriver_config.proxy_port = config.proxy_settings.port_value
|
46
|
+
chromedriver_config.proxy_user = config.proxy_settings.user_value
|
47
|
+
chromedriver_config.proxy_pass = config.proxy_settings.pass_value
|
55
48
|
|
56
|
-
|
49
|
+
chromedriver_config.install_dir = config.chromedriver_settings.install_dir_value
|
57
50
|
end
|
58
51
|
end
|
59
52
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
@remote_browser_url = nil
|
67
|
-
@cookies = {}
|
68
|
-
@headers = {}
|
69
|
-
@auth = nil
|
70
|
-
@headless = !Rails.env.development?
|
71
|
-
@chromedriver_port = 0
|
72
|
-
@chrome_session_args = Bidi2pdf::Bidi::Session::DEFAULT_CHROME_ARGS
|
73
|
-
|
74
|
-
@proxy_addr = nil
|
75
|
-
@proxy_port = nil
|
76
|
-
@proxy_user = nil
|
77
|
-
@proxy_pass = nil
|
78
|
-
@install_dir = nil
|
53
|
+
def use_local_chromedriver?
|
54
|
+
!use_remote_browser?
|
55
|
+
end
|
56
|
+
|
57
|
+
def use_remote_browser?
|
58
|
+
config.render_remote_settings.browser_url_value.present?
|
79
59
|
end
|
80
60
|
|
81
61
|
def logger
|
82
|
-
|
62
|
+
config.general_options.logger_value&.tagged("bidi2pdf-rails")
|
83
63
|
end
|
84
64
|
end
|
85
65
|
|
86
|
-
self
|
66
|
+
that = self
|
67
|
+
ActiveSupport.on_load(:action_controller_base, run_once: true) do
|
68
|
+
that.configure # apply the default configuration at load time
|
69
|
+
end
|
87
70
|
end
|
@@ -1,8 +1,16 @@
|
|
1
1
|
Description:
|
2
|
-
|
2
|
+
Generates a configuration file for Bidi2pdfRails in config/initializers/bidi2pdf_rails.rb
|
3
|
+
and adds development environment settings.
|
3
4
|
|
4
5
|
Example:
|
5
|
-
bin/rails generate initializer
|
6
|
+
bin/rails generate bidi2pdf_rails:initializer
|
6
7
|
|
7
|
-
|
8
|
-
|
8
|
+
# With options
|
9
|
+
bin/rails generate bidi2pdf_rails:initializer --quiet # Skip interactive prompts
|
10
|
+
bin/rails generate bidi2pdf_rails:initializer --force # Overwrite existing config
|
11
|
+
|
12
|
+
This will create:
|
13
|
+
config/initializers/bidi2pdf_rails.rb
|
14
|
+
|
15
|
+
And add settings to:
|
16
|
+
config/environments/development.rb
|
@@ -1,43 +1,72 @@
|
|
1
1
|
module Bidi2pdfRails
|
2
2
|
class InitializerGenerator < Rails::Generators::Base
|
3
3
|
source_root File.expand_path("templates", __dir__)
|
4
|
-
desc "Generates a config/initializers/bidi2pdf.rb config file"
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
def self.infer_option_type(default)
|
6
|
+
case default
|
7
|
+
when true, false then :boolean
|
8
|
+
when Numeric then :numeric
|
9
|
+
when Hash then :hash
|
10
|
+
when Array then :array
|
11
|
+
when Proc then :string
|
12
|
+
else :string
|
13
|
+
end
|
14
|
+
end
|
11
15
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@proxy = yes?("Use a proxy server? (y/n)", :green)
|
16
|
+
def self.normalize_group(key)
|
17
|
+
key.to_s.sub(/(_settings|_options)$/, "")
|
18
|
+
end
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
+
def self.with_group_config
|
21
|
+
that = self
|
22
|
+
Bidi2pdfRails::Config::CONFIG_OPTIONS.each_pair do |group_key, group_config|
|
23
|
+
group_prefix = that.normalize_group(group_key)
|
24
|
+
yield group_key, group_prefix, group_config
|
20
25
|
end
|
26
|
+
end
|
21
27
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
28
|
+
def self.with_group_option
|
29
|
+
with_group_config do |group_key, group_prefix, group_config|
|
30
|
+
group_config[:options].each do |opt|
|
31
|
+
yield group_key, group_prefix, opt
|
32
|
+
end
|
26
33
|
end
|
34
|
+
end
|
35
|
+
|
36
|
+
with_group_option do |_group_key, group_prefix, opt|
|
37
|
+
next unless opt[:ask]
|
38
|
+
|
39
|
+
name = "#{group_prefix}_#{opt[:name]}"
|
40
|
+
type = infer_option_type(opt[:default])
|
41
|
+
default = opt[:default_as_str] || opt[:default]
|
42
|
+
|
43
|
+
class_option name,
|
44
|
+
type: type,
|
45
|
+
desc: opt[:desc],
|
46
|
+
default: default,
|
47
|
+
enum: opt[:limited_to]
|
48
|
+
end
|
27
49
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
50
|
+
def ask_questions
|
51
|
+
@answers = {}
|
52
|
+
|
53
|
+
return if options[:quiet]
|
54
|
+
|
55
|
+
self.class.with_group_config do |_group_key, group_prefix, group_config|
|
56
|
+
next unless group_config[:ask]
|
57
|
+
if group_config[:ask]
|
58
|
+
next unless yes?(group_config[:ask], :green)
|
59
|
+
end
|
60
|
+
|
61
|
+
group_config[:options].select { |opt| opt[:ask] }.each do |opt|
|
62
|
+
option_key = "#{group_prefix}_#{opt[:name]}".to_sym
|
63
|
+
next if cli_option_set?(option_key, opt)
|
64
|
+
|
65
|
+
@answers[option_key] = prompt_for_option(opt)
|
37
66
|
end
|
38
|
-
@pdf_print_background = yes?("Print background graphics? (y/n)", :green)
|
39
|
-
@pdf_scale = ask("PDF scale (e.g., 1.0):", :yellow)
|
40
67
|
end
|
68
|
+
|
69
|
+
@answers.compact!
|
41
70
|
end
|
42
71
|
|
43
72
|
def generate_config
|
@@ -48,9 +77,10 @@ module Bidi2pdfRails
|
|
48
77
|
|
49
78
|
def inject_environment_config
|
50
79
|
env_file = "config/environments/development.rb"
|
80
|
+
env_path = File.join(destination_root, env_file)
|
51
81
|
|
52
|
-
if File.exist?(
|
53
|
-
if File.read(
|
82
|
+
if File.exist?(env_path)
|
83
|
+
if File.read(env_path).include?("config.x.bidi2pdf_rails")
|
54
84
|
say_status :skipped, "Bidi2PDF settings already present in #{env_file}", :yellow
|
55
85
|
else
|
56
86
|
content = <<~RUBY.gsub(/^(?=[\w#])/, " ")
|
@@ -69,5 +99,81 @@ module Bidi2pdfRails
|
|
69
99
|
say_status :error, "Could not find #{env_file}", :red
|
70
100
|
end
|
71
101
|
end
|
102
|
+
|
103
|
+
no_commands do
|
104
|
+
def cli_option_set?(option_key, opt_def)
|
105
|
+
return false unless options.key?(option_key.to_s)
|
106
|
+
|
107
|
+
default = opt_def[:default_as_str] || opt_def[:default]
|
108
|
+
options[option_key.to_s].to_s != default.to_s
|
109
|
+
end
|
110
|
+
|
111
|
+
def prompt_for_option(opt)
|
112
|
+
type = self.class.infer_option_type(opt[:default])
|
113
|
+
|
114
|
+
if type == :boolean
|
115
|
+
question = opt[:desc].match?(/y\/n/i) ? opt[:desc] : "#{opt[:desc]} (y/n)?"
|
116
|
+
yes?(question, opt[:color])
|
117
|
+
else
|
118
|
+
opts = {
|
119
|
+
default: opt[:default_as_str] || opt[:default],
|
120
|
+
limited_to: opt[:limited_to],
|
121
|
+
echo: !opt[:secret]
|
122
|
+
}.compact
|
123
|
+
|
124
|
+
ask(opt[:desc], opt[:color], **opts)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def normalize_group(key)
|
129
|
+
self.class.normalize_group(key)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def changed_by_user?(full_top_level_name, option_name)
|
136
|
+
top_level_name = normalize_group full_top_level_name
|
137
|
+
|
138
|
+
full_qual_option_name = "#{top_level_name}_#{option_name}".to_sym
|
139
|
+
return false unless options.key?(full_qual_option_name.to_s)
|
140
|
+
|
141
|
+
option_def = Bidi2pdfRails::Config::CONFIG_OPTIONS.dig(full_top_level_name.to_sym, :options).find { |opt| opt[:name] == option_name.to_sym }
|
142
|
+
default = option_def[:default_as_str] ? option_def[:default_as_str] : option_def[:default]
|
143
|
+
|
144
|
+
current_value = get_option_value(top_level_name, option_name)
|
145
|
+
|
146
|
+
return false if default.nil? && current_value.empty?
|
147
|
+
return true if default.nil? && current_value.present?
|
148
|
+
|
149
|
+
!current_value.to_s.match /#{Regexp.escape(default.to_s)}/
|
150
|
+
end
|
151
|
+
|
152
|
+
def get_option_value(top_level_name, option_name)
|
153
|
+
top_level_name = top_level_name.to_s.sub(/(_settings)|(_options)$/, "")
|
154
|
+
full_qual_option_name = "#{top_level_name}_#{option_name}".to_sym
|
155
|
+
|
156
|
+
result = if @answers.key?(full_qual_option_name)
|
157
|
+
@answers[full_qual_option_name]
|
158
|
+
elsif options.key?(full_qual_option_name.to_s)
|
159
|
+
options[full_qual_option_name.to_s]
|
160
|
+
else
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
|
164
|
+
if result.is_a?(String)
|
165
|
+
if result.match(/(^\s+->\s+{)|(.*Rails\.)/) || numeric?(result)
|
166
|
+
return result
|
167
|
+
end
|
168
|
+
'"' + result + '"'
|
169
|
+
else
|
170
|
+
result
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def numeric?(string)
|
175
|
+
# Float/Integer conversion with rescue catches most numeric formats
|
176
|
+
true if Float(string) rescue false
|
177
|
+
end
|
72
178
|
end
|
73
179
|
end
|