diff --git a/.rubocop.yml b/.rubocop.yml index d88da1b..069c943 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,8 @@ +require: rubocop-rspec + AllCops: - TargetRubyVersion: 2.3 + TargetRubyVersion: 3.0 + NewCops: enable Naming/FileName: Enabled: false @@ -13,12 +16,15 @@ Naming/AccessorMethodName: Style/ClassAndModuleChildren: Enabled: false -Metrics/LineLength: +Layout/LineLength: Max: 120 Metrics/MethodLength: Enabled: false +Metrics/ModuleLength: + Enabled: false + Metrics/AbcSize: Enabled: false @@ -46,7 +52,7 @@ Style/Documentation: Style/GuardClause: Enabled: false -Naming/UncommunicativeMethodParamName: +Naming/MethodParameterName: Enabled: false Style/EvalWithLocation: diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..fa7adc7 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.3.5 diff --git a/Gemfile b/Gemfile index 9a78deb..692377d 100644 --- a/Gemfile +++ b/Gemfile @@ -3,3 +3,9 @@ source 'https://rubygems.org/' gemspec + +group :development do + gem 'rspec' + gem 'rubocop' + gem 'rubocop-rspec' +end diff --git a/Gemfile.lock b/Gemfile.lock index 8dafb49..8d3b006 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,46 +7,55 @@ PATH GEM remote: https://rubygems.org/ specs: - Ascii85 (1.0.2) - afm (0.2.0) - ast (2.4.0) - diff-lcs (1.2.5) - hashery (2.1.1) - jaro_winkler (1.5.2) - parallel (1.12.1) - parser (2.5.3.0) - ast (~> 2.4.0) - pdf-reader (1.3.3) - Ascii85 (~> 1.0.0) - afm (~> 0.2.0) - hashery (~> 2.0) - ruby-rc4 - ttfunk - powerpack (0.1.2) - prawn (0.12.0) - pdf-reader (>= 0.9.0) - ttfunk (~> 1.0.2) - rainbow (3.0.0) - rspec (2.14.1) - rspec-core (~> 2.14.0) - rspec-expectations (~> 2.14.0) - rspec-mocks (~> 2.14.0) - rspec-core (2.14.7) - rspec-expectations (2.14.4) - diff-lcs (>= 1.1.3, < 2.0) - rspec-mocks (2.14.4) - rubocop (0.62.0) - jaro_winkler (~> 1.5.1) + ast (2.4.2) + bigdecimal (3.1.8) + diff-lcs (1.5.1) + json (2.7.2) + language_server-protocol (3.17.0.3) + matrix (0.4.2) + parallel (1.26.3) + parser (3.3.5.0) + ast (~> 2.4.1) + racc + pdf-core (0.10.0) + prawn (2.5.0) + matrix (~> 0.4) + pdf-core (~> 0.10.0) + ttfunk (~> 1.8) + racc (1.8.1) + rainbow (3.1.1) + regexp_parser (2.9.2) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.1) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.1) + rubocop (1.66.1) + json (~> 2.3) + language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 2.5, != 2.5.1.1) - powerpack (~> 0.1) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.4, < 3.0) + rubocop-ast (>= 1.32.2, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (~> 1.4.0) - ruby-progressbar (1.10.0) - ruby-rc4 (0.1.5) - ttfunk (1.0.3) - unicode-display_width (1.4.1) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.32.3) + parser (>= 3.3.1.0) + rubocop-rspec (3.1.0) + rubocop (~> 1.61) + ruby-progressbar (1.13.0) + ttfunk (1.8.0) + bigdecimal (~> 3.1) + unicode-display_width (2.6.0) PLATFORMS ruby @@ -55,6 +64,7 @@ DEPENDENCIES prawn-blank! rspec rubocop + rubocop-rspec BUNDLED WITH - 1.17.1 + 2.5.21 diff --git a/Rakefile b/Rakefile index 9d8f0ac..f102b7a 100644 --- a/Rakefile +++ b/Rakefile @@ -19,15 +19,11 @@ end gem 'hoe', '>=2.0.0' require 'hoe' -require 'spec/version' -require 'spec/rake/spectask' -require 'spec/ruby' - Spec::Rake::SpecTask.new('spec') do |t| t.spec_files = FileList['spec/**/*.rb'] end desc 'Look for TODO and FIXME tags in the code' -task :todo do +task todo: :environment do egrep(/(FIXME|TODO|TBD)/) end diff --git a/lib/prawn/blank.rb b/lib/prawn/blank.rb index d9930bc..f14f3cc 100644 --- a/lib/prawn/blank.rb +++ b/lib/prawn/blank.rb @@ -91,12 +91,7 @@ def get_actual_page_dimensions(page) page_rotation = get_page_rotation(page) - if [90, 270].include?(page_rotation) - swap_width = page_width - - page_width = page_height - page_height = swap_width - end + page_width, page_height = page_height, page_width if [90, 270].include?(page_rotation) [page_width, page_height] end diff --git a/lib/prawn/blank/appearance.rb b/lib/prawn/blank/appearance.rb index 3be1826..9bc71e0 100755 --- a/lib/prawn/blank/appearance.rb +++ b/lib/prawn/blank/appearance.rb @@ -43,7 +43,7 @@ def xobject_matrix(width, height) raise "Unhandled page rotation for xobject_matrix! #{page_rotation}" end - def render(dict) + def render(dict, &block) dict = { Type: :XObject, Subtype: :Form, @@ -51,9 +51,7 @@ def render(dict) }.merge(dict) result = @document.ref!(dict) - @document.state.page.stamp_stream(result) do - yield - end + @document.state.page.stamp_stream(result, &block) @document.acroform.add_resources(result.data[:Resources]) result end @@ -82,14 +80,14 @@ def button(element) alias button_over button alias button_down button - def checkbox_off(element, _cache_key = :checkbox_off, mousedown = false) + def checkbox_off(element, _cache_key = :checkbox_off, mousedown: false) element.width = 10 if !element.width || (element.width <= 0) element.height = 10 if !element.height || (element.height <= 0) width = element.width height = element.height # style = element.style ||= Prawn::ColorStyle(@document, 'ffffff', '888888') - style = element.style ||= { + element.style ||= { BC: [0], BG: [1] } @@ -120,17 +118,17 @@ def checkbox_off(element, _cache_key = :checkbox_off, mousedown = false) alias checkbox_off_over checkbox_off # alias checkbox_off_down checkbox_off def checkbox_off_down(element) - checkbox_off(element, :checkbox_off_down, :down) + checkbox_off(element, :checkbox_off_down, mousedown: true) end - def checkbox_on(element, _cache_key = :checkbox_on, mousedown = false) + def checkbox_on(element, _cache_key = :checkbox_on, mousedown: false) element.width = 10 if !element.width || (element.width <= 0) element.height = 10 if !element.height || (element.height <= 0) width = element.width height = element.height # style = element.style ||= Prawn::ColorStyle(@document, 'ffffff', '888888') # border_style = element.border_style ||= Prawn::BorderStyle(@document, 4) - style = element.style ||= { + element.style ||= { BC: [0], BG: [1] } @@ -181,7 +179,8 @@ def checkbox_on(element, _cache_key = :checkbox_on, mousedown = false) # x y m: Begin a new subpath by moving the current point to coordinates (x, y) # x1 y1 x2 y2 x3 y3 c: Append a cubic Bézier curve to the current path # x y l: Append a straight line segment from the current point to the point (x, y) - # h: Close the current subpath by appending a straight line segment from the current point to the starting point of the subpath. + # h: Close the current subpath by appending a straight line segment from the + # current point to the starting point of the subpath. stream_ref.stream << %( #{bg_color} g @@ -209,10 +208,10 @@ def checkbox_on(element, _cache_key = :checkbox_on, mousedown = false) alias checkbox_on_over checkbox_on # alias checkbox_on_down checkbox_on def checkbox_on_down(element) - checkbox_on(element, :checkbox_on_down, :down) + checkbox_on(element, :checkbox_on_down, mousedown: true) end - def radio_off(element, cache_key = :radio_off, mousedown = false) + def radio_off(element, cache_key = :radio_off, mousedown: false) element.width = 10 if !element.width || (element.width <= 0) element.height = 10 if !element.height || (element.height <= 0) width = element.width @@ -273,10 +272,10 @@ def radio_off(element, cache_key = :radio_off, mousedown = false) alias radio_off_over radio_off # alias radio_off_down radio_off def radio_off_down(element) - radio_off(element, :radio_off_down, :down) + radio_off(element, :radio_off_down, mousedown: true) end - def radio_on(element, _cache_key = :radio_on, mousedown = false) + def radio_on(element, _cache_key = :radio_on, mousedown: false) element.width = 10 if !element.width || (element.width <= 0) element.height = 10 if !element.height || (element.height <= 0) width = element.width @@ -340,32 +339,30 @@ def radio_on(element, _cache_key = :radio_on, mousedown = false) alias radio_on_over radio_on # alias radio_on_down radio_on def radio_on_down(element) - radio_on(element, :radio_on_down, :down) + radio_on(element, :radio_on_down, mousedown: true) end # For DA instead of AP def text_field_default_appearance(element) - text_style = element.text_style ||= Prawn::TextStyle(@document,"Helvetica",10,'000000') + text_style = element.text_style ||= Prawn::TextStyle(@document, 'Helvetica', 10, '000000') # Set border width to 0, don't add any borders by default element.border_style ||= Prawn::BorderStyle(@document, 0) - if !element.width or element.width <= 0 - element.width = 100 - end - if !element.height or element.height <= 0 + element.width = 100 if !element.width || (element.width <= 0) + if !element.height || (element.height <= 0) element.height = text_style.size + 6 # + 2 * border_style[:W] end width = element.width height = element.height - style = element.style || Prawn::ColorStyle(@document,'ffffff','000000') + style = element.style || Prawn::ColorStyle(@document, 'ffffff', '000000') multiline = element.multiline value = element.value font_ref = document.state.page.fonts[text_style.font_identifier] descent_ratio = 0.23 - vertical_offset = text_style.size * descent_ratio + 1.25 + vertical_offset = (text_style.size * descent_ratio) + 1.25 if value.blank? || value.ascii_only? return cached( @@ -389,66 +386,64 @@ def text_field_default_appearance(element) render( BBox: [0, 0, width, height], FormType: 1, - Matrix: xobject_matrix(width, height), + Matrix: xobject_matrix(width, height) ) do document.add_content '/Tx BMC' document.canvas do document.save_font do document.transparent(element.text_box_opacity || 1) do - document.stroke_color( *denormalize_color(style[:BC]) ) - document.fill_color( *denormalize_color(style[:BG]) ) - - # render background - if element.text_box_background_color.present? - document.fill_color(element.text_box_background_color) - document.fill_rectangle( [0, height], width, height) - end - - # document.line_width(border_style[:W]) - # bw = border_style[:W]/2.0 - - next unless value.present? - - if text_style - document.font(text_style.font, size: text_style.size, style: text_style.style ) - document.stroke_color( *text_style.color ) - document.fill_color( *text_style.color ) - end - - # document.draw_text(value, at: [0, [0, height - document.font_size - 1.5].max ] ) - - # text_offset_y = [height - document.font_size - 1.5].max - - text_box_args = { - # at: [0, text_offset_y], - at: [0, height], - width: width, - height: height, - align: element.text_box_align, - valign: element.text_box_valign, - overflow: element.text_box_overflow, - min_font_size: 5, - single_line: element.multiline == 0, - character_spacing: element.text_box_character_spacing, - direction: element.text_box_text_direction, - } - - text_options = { text: value } - - if element.text_box_strikethrough - text_options[:styles] = [:strikethrough] - end - - formatted_text_array = [text_options] - - begin - document.formatted_text_box( - formatted_text_array, - text_box_args - ) - rescue Prawn::Errors::CannotFit - document.draw_text value, at: [0, height], direction: element.text_box_text_direction - end + document.stroke_color(*denormalize_color(style[:BC])) + document.fill_color(*denormalize_color(style[:BG])) + + # render background + if element.text_box_background_color.present? + document.fill_color(element.text_box_background_color) + document.fill_rectangle([0, height], width, height) + end + + # document.line_width(border_style[:W]) + # bw = border_style[:W]/2.0 + + next if value.blank? + + if text_style + document.font(text_style.font, size: text_style.size, style: text_style.style) + document.stroke_color(*text_style.color) + document.fill_color(*text_style.color) + end + + # document.draw_text(value, at: [0, [0, height - document.font_size - 1.5].max ] ) + + # text_offset_y = [height - document.font_size - 1.5].max + + text_box_args = { + # at: [0, text_offset_y], + at: [0, height], + width: width, + height: height, + align: element.text_box_align, + valign: element.text_box_valign, + overflow: element.text_box_overflow, + min_font_size: 5, + single_line: element.multiline == 0, + character_spacing: element.text_box_character_spacing, + direction: element.text_box_text_direction + } + + text_options = { text: value } + + text_options[:styles] = [:strikethrough] if element.text_box_strikethrough + + formatted_text_array = [text_options] + + begin + document.formatted_text_box( + formatted_text_array, + text_box_args + ) + rescue Prawn::Errors::CannotFit + document.draw_text value, at: [0, height], direction: element.text_box_text_direction + end end end end @@ -483,7 +478,7 @@ def text_field_default_appearance(element) W n BT -#{text_style.to_s} +#{text_style} 2 #{vertical_offset} Td (#{value}) Tj ET @@ -491,7 +486,6 @@ def text_field_default_appearance(element) EMC ) stream_ref - end protected @@ -502,11 +496,12 @@ def cached(*args) def denormalize_color(color) s = color.size - if s == 1 # gray + case s + when 1 # gray return [0, 0, 0, color[0]] - elsif s == 3 # rgb + when 3 # rgb return Prawn::Graphics::Color.rgb2hex(color.map { |component| component * 255.0 }) - elsif s == 4 # cmyk + when 4 # cmyk return color.map { |component| component * 100.0 } end diff --git a/lib/prawn/blank/field.rb b/lib/prawn/blank/field.rb index 20a05f7..3076dca 100644 --- a/lib/prawn/blank/field.rb +++ b/lib/prawn/blank/field.rb @@ -3,15 +3,17 @@ class Prawn::Blank::Field < Prawn::Blank::FieldBase # Returns the ZapfDingbats character code for the checkmark (between 3 and 8) def check_zapf_char - check_char = check_string - if check_char&.match?(%r{^Ϩ\d;$}) - check_char = HTMLEntities.new.decode(check_char) - end - check_char = "✔" unless check_char&.length == 1 - check_zapf_char = (check_string.ord || 0) - 10000 - if check_zapf_char < 3 || check_zapf_char > 8 - check_zapf_char = 4 - end + # TODO: verify intended functionality and consider reimplementation + # This code was probably intended to use check_char as a replacement for check_string + # Commented out for now to avoid rubocop complaints + # + # check_char = check_string + # if check_char&.match?(%r{^Ϩ\d;$}) + # check_char = HTMLEntities.new.decode(check_char) + # end + # check_char = "✔" unless check_char&.length == 1 + check_zapf_char = (check_string.ord || 0) - 10_000 + check_zapf_char = 4 if check_zapf_char < 3 || check_zapf_char > 8 check_zapf_char.to_s end diff --git a/lib/prawn/blank/field_base.rb b/lib/prawn/blank/field_base.rb index bedae14..605b31e 100755 --- a/lib/prawn/blank/field_base.rb +++ b/lib/prawn/blank/field_base.rb @@ -29,62 +29,102 @@ class Prawn::Blank::FieldBase < PDF::Core::Reference }.freeze class << self - def field_attr_accessor(name, key, inheritable = true) - class_eval <