├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── lib ├── nguyen.rb └── nguyen │ ├── fdf.rb │ ├── pdf.rb │ ├── pdftk_wrapper.rb │ ├── version.rb │ └── xfdf.rb ├── nguyen.gemspec └── test ├── fdf_test.rb ├── fixtures └── form.pdf ├── pdf_test.rb ├── pdftk_wrapper_test.rb ├── test_helper.rb └── xfdf_test.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .rvmrc 3 | .tool-versions 4 | .idea 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.5 4 | - 2.6 5 | - 2.7 6 | before_script: 7 | - sudo apt-get install pdftk 8 | script: 9 | - bundle exec rake test 10 | notifications: 11 | email: 12 | - trung.le@ruby-journal.com 13 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Filing an issue 2 | 3 | When filing an issue, please provide these details: 4 | 5 | * A comprehensive list of steps to reproduce the issue. 6 | * The version of Nguyen. 7 | * Any relevant stack traces ("Full trace" preferred) 8 | 9 | In 99% of cases, this information is enough to determine the cause and solution to the problem that is being described. 10 | 11 | Any issue that is open for 14 days without actionable information or activity will be marked as "stalled" and then closed. Stalled issues can be re-opened if the information requested is provided. 12 | 13 | ## Pull requests 14 | 15 | We gladly accept pull requests to fix bugs and, in some circumstances, add new features to Spree. 16 | 17 | Here's a quick guide: 18 | 19 | 1. Fork the repo. 20 | 21 | 2. Run the tests. We only take pull requests with passing tests, and it's great 22 | to know that you have a clean slate: 23 | 24 | bundle install 25 | bundle exec rake test 26 | 27 | 3. Add a test for your change. Only refactoring and documentation changes 28 | require no new tests. If you are adding functionality or fixing a bug, we need 29 | a test! 30 | 31 | 4. Make the test pass. 32 | 33 | 5. Push to your fork and submit a pull request. If the changes will apply cleanly to the latest stable branches and master branch, you will only need to submit one pull request. 34 | 35 | At this point you're waiting on us. We like to at least comment on, if not 36 | accept, pull requests within three business days (and, typically, one business 37 | day). We may suggest some changes or improvements or alternatives. 38 | 39 | Syntax: 40 | 41 | * Two spaces, no tabs. 42 | * No trailing whitespace. Blank lines should not have any space. 43 | * Prefer &&/|| over and/or. 44 | * `MyClass.my_method(my_arg)` not `my_method( my_arg )` or my_method my_arg. 45 | * `a = b` and not `a=b`. 46 | * `a_method { |block| ... }` and not `a_method { | block | ... }` 47 | * Follow the conventions you see used in the source already. 48 | 49 | And in case we didn't emphasize it enough: we love tests! 50 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | group :development do 6 | gem 'rake' 7 | end -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | nguyen (1.0.3) 5 | nokogiri (~> 1.10) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | mini_portile2 (2.6.1) 11 | minitest (5.5.1) 12 | nokogiri (1.12.5) 13 | mini_portile2 (~> 2.6.1) 14 | racc (~> 1.4) 15 | racc (1.5.2) 16 | rake (13.0.1) 17 | 18 | PLATFORMS 19 | ruby 20 | 21 | DEPENDENCIES 22 | minitest 23 | nguyen! 24 | rake 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2014 - 2020 Trung Lê 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nguyên the PDF Field Merger 2 | 3 | A very lightweight library that fill PDF forms using XFDF/FDF with pdftk 4 | 5 | You could download pdftk at http://www.accesspdf.com/pdftk/ 6 | 7 | Nguyên is a fork of Jens Krämer's pdf-forms with addition of filling forms with XFDF feature. 8 | 9 | [![Build Status](https://secure.travis-ci.org/ruby-journal/nguyen.png)](http://travis-ci.org/ruby-journal/nguyen) 10 | [![Code Climate](https://codeclimate.com/github/ruby-journal/nguyen/badges/gpa.svg)](https://codeclimate.com/github/ruby-journal/nguyen) 11 | [![From Vietnam with <3](https://raw.githubusercontent.com/webuild-community/badge/master/svg/love.svg)](https://webuild.community) 12 | [![Made in Vietnam](https://raw.githubusercontent.com/webuild-community/badge/master/svg/made.svg)](https://webuild.community) 13 | [![Built with WeBuild](https://raw.githubusercontent.com/webuild-community/badge/master/svg/WeBuild.svg)](https://webuild.community) 14 | 15 | ## EXAMPLE: 16 | 17 | ### FDF creation 18 | 19 | ```ruby 20 | fdf = Nguyen::Fdf.new(key: 'value', other_key: 'other value') 21 | # use to_fdf if you just want the FDF data, without writing it to a file 22 | puts fdf.to_fdf 23 | # write fdf file 24 | fdf.save_to('path/to/file.fdf') 25 | ``` 26 | 27 | ### XFDF creation 28 | 29 | ```ruby 30 | xfdf = Nguyen::Xfdf.new(key: 'value', other_key: 'other value') 31 | # use to_xfdf if you just want the XFDF data, without writing it to a file 32 | puts xfdf.to_xfdf 33 | # write xfdf file 34 | xfdf.save_to('path/to/file.xfdf') 35 | ``` 36 | 37 | ### Query form fields and fill out PDF forms with pdftk 38 | 39 | ```ruby 40 | # adjust the pdftk path to suit your pdftk installation 41 | pdftk = Nguyen::PdftkWrapper.new('/usr/local/bin/pdftk') 42 | 43 | # find out the field names that are present in form.pdf 44 | pdftk.get_field_names('path/to/form.pdf') 45 | 46 | # take form.pdf, set the 'foo' field to 'bar' and save the document to myform.pdf 47 | 48 | # with fdf 49 | fdf = Nguyen::Fdf.new(foo: 'bar') 50 | pdftk.fill_form('/path/to/form.pdf', 'myform.pdf', fdf) 51 | 52 | # with xfdf 53 | xfdf = Nguyen::Xfdf.new(foo: 'bar') 54 | pdftk.fill_form('/path/to/form.pdf', 'myform.pdf', xfdf) 55 | 56 | # will work with xfdf or fdf xml string directly as well 57 | xfdf_string = < 59 | bar 60 | XML 61 | # or xfdf_string = Nguyen::Xfdf.new(foo: 'bar').to_xfdf 62 | pdftk.fill_form('/path/to/form', 'myform.pdf', xfdf_string) 63 | ``` 64 | 65 | ## INSTALL: 66 | 67 | gem install nguyen 68 | 69 | ## Source Code: 70 | 71 | git clone http://github.com/ruby-journal/nguyen.git 72 | 73 | ## Contribution: 74 | 75 | I greatly welcome contributions, please feel free to fork and submit pull request. 76 | 77 | ## LICENSE 78 | 79 | see [LICENSE](LICENSE) 80 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | begin 4 | Bundler.setup(:default, :development) 5 | rescue Bundler::BundlerError => e 6 | $stderr.puts e.message 7 | $stderr.puts "Run `bundle install` to install missing gems" 8 | exit e.status_code 9 | end 10 | require 'rake' 11 | require 'rake/testtask' 12 | 13 | desc 'Test the library.' 14 | Rake::TestTask.new(:test) do |t| 15 | t.libs << 'lib' << 'test' 16 | t.pattern = 'test/**/*_test.rb' 17 | t.verbose = true 18 | end 19 | 20 | gemspec = eval(File.read('nguyen.gemspec')) 21 | 22 | task :build => "#{gemspec.full_name}.gem" 23 | 24 | file "#{gemspec.full_name}.gem" => gemspec.files + ['nguyen.gemspec'] do 25 | system 'gem build nguyen.gemspec' 26 | system "gem install nguyen-#{Nguyen::VERSION.dup}.gem" 27 | end 28 | -------------------------------------------------------------------------------- /lib/nguyen.rb: -------------------------------------------------------------------------------- 1 | require_relative 'nguyen/fdf' 2 | require_relative 'nguyen/xfdf' 3 | require_relative 'nguyen/pdf' 4 | require_relative 'nguyen/pdftk_wrapper' 5 | -------------------------------------------------------------------------------- /lib/nguyen/fdf.rb: -------------------------------------------------------------------------------- 1 | module Nguyen 2 | 3 | # Map keys and values to Adobe's FDF format. 4 | # 5 | # Straight port of Perl's PDF::FDF::Simple by Steffen Schwigon. 6 | # Parsing FDF files is not supported (yet). 7 | class Fdf 8 | 9 | attr_reader :options 10 | 11 | def initialize(data = {}, options = {}) 12 | @data = data 13 | @options = { 14 | file: nil, 15 | ufile: nil, 16 | id: nil 17 | }.merge(options) 18 | end 19 | 20 | # generate FDF content 21 | def to_fdf 22 | fdf = header 23 | 24 | @data.each do |key, value| 25 | if Hash === value 26 | value.each do |sub_key, sub_value| 27 | fdf << field("#{key}_#{sub_key}", sub_value) 28 | end 29 | else 30 | fdf << field(key, value) 31 | end 32 | end 33 | 34 | fdf << footer 35 | return fdf 36 | end 37 | 38 | # write fdf content to path 39 | def save_to(path) 40 | File.write(path, to_fdf) 41 | end 42 | 43 | protected 44 | 45 | def header 46 | header = "%FDF-1.2\n\n1 0 obj\n<<\n/FDF << /Fields 2 0 R" 47 | 48 | # /F 49 | header << "/F (#{options[:file]})" if options[:file] 50 | # /UF 51 | header << "/UF (#{options[:ufile]})" if options[:ufile] 52 | # /ID 53 | header << "/ID[" << options[:id].join << "]" if options[:id] 54 | 55 | header << ">>\n>>\nendobj\n2 0 obj\n[" 56 | return header 57 | end 58 | 59 | def field(key, value) 60 | value_string = case value 61 | when TrueClass 62 | '/1' 63 | when FalseClass 64 | '/0' 65 | when Array 66 | '[' + value.map { |v| "(#{quote(v)})" }.join + ']' 67 | else 68 | "(#{quote(value)})" 69 | end 70 | "<<\n/T(#{key})\n/V #{value_string}\n>>\n" 71 | end 72 | 73 | def quote(value) 74 | value.to_s.strip. 75 | gsub( /\\/, '\\' ). 76 | gsub( /\(/, '\(' ). 77 | gsub( /\)/, '\)' ). 78 | gsub( /\n/, '\r' ) 79 | end 80 | 81 | FOOTER =<<-EOFOOTER 82 | ] 83 | endobj 84 | trailer 85 | << 86 | /Root 1 0 R 87 | 88 | >> 89 | %%EOF 90 | EOFOOTER 91 | 92 | def footer 93 | FOOTER 94 | end 95 | 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /lib/nguyen/pdf.rb: -------------------------------------------------------------------------------- 1 | module Nguyen 2 | class Pdf 3 | attr_reader :path 4 | 5 | def initialize(path, pdftk) 6 | @path = path 7 | raise IOError unless File.readable?(path) 8 | @pdftk = pdftk 9 | end 10 | 11 | def fields 12 | @fields ||= read_fields 13 | end 14 | 15 | protected 16 | 17 | def read_fields 18 | field_output = @pdftk.call_pdftk path, 'dump_data_fields_utf8' 19 | @fields = field_output.split("\n").map do |field_text| 20 | if field_text =~ /^FieldName: (.+)$/ 21 | $1 22 | end 23 | end.compact.uniq 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/nguyen/pdftk_wrapper.rb: -------------------------------------------------------------------------------- 1 | require 'tempfile' 2 | module Nguyen 3 | class PdftkError < StandardError 4 | end 5 | 6 | # Wraps calls to PdfTk 7 | class PdftkWrapper 8 | 9 | attr_reader :pdftk, :options 10 | 11 | # PdftkWrapper.new('/usr/bin/pdftk', :flatten => true, :encrypt => true, :encrypt_options => 'allow Printing') 12 | def initialize(pdftk_path, options = {}) 13 | @pdftk = pdftk_path 14 | @options = options 15 | end 16 | 17 | # pdftk.fill_form '/path/to/form.pdf', '/path/to/destination.pdf', xfdf_or_fdf_object or xfdf_or_fdf_string 18 | def fill_form(template, destination, form_data) 19 | tmp = Tempfile.new('pdf_forms-fdf') 20 | tmp.close 21 | form_data.respond_to?(:save_to) ? form_data.save_to(tmp.path) : File.write(tmp.path, form_data) 22 | command = pdftk_command %Q("#{template}"), 'fill_form', %Q("#{tmp.path}"), 'output', destination, add_options(tmp.path) 23 | output = %x{#{command}} 24 | unless File.readable?(destination) && File.size(destination) > 0 25 | raise PdftkError.new("failed to fill form with command\n#{command}\ncommand output was:\n#{output}") 26 | end 27 | ensure 28 | tmp.unlink if tmp 29 | end 30 | 31 | # pdftk.read '/path/to/form.pdf' 32 | # returns an instance of Nguyen::Pdf representing the given template 33 | def read(path) 34 | Pdf.new path, self 35 | end 36 | 37 | def get_field_names(template) 38 | read(template).fields 39 | end 40 | 41 | def call_pdftk(*args) 42 | %x{#{pdftk_command args}} 43 | end 44 | 45 | def cat(*files,output) 46 | files = files[0] if files[0].class == Array 47 | input = files.map{|f| %Q(#{f})} 48 | call_pdftk(*input,'output',output) 49 | end 50 | 51 | protected 52 | 53 | def pdftk_command(*args) 54 | "#{pdftk} #{args.flatten.compact.join ' '} 2>&1" 55 | end 56 | 57 | def add_options(pwd) 58 | return if options.empty? 59 | opt_args = [] 60 | if options[:flatten] 61 | opt_args << 'flatten' 62 | end 63 | if options[:encrypt] 64 | opt_args.concat ['encrypt_128bit', 'owner_pw', pwd, options[:encrypt_options]] 65 | end 66 | opt_args 67 | end 68 | 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /lib/nguyen/version.rb: -------------------------------------------------------------------------------- 1 | module Nguyen 2 | VERSION = '1.0.3' 3 | end 4 | -------------------------------------------------------------------------------- /lib/nguyen/xfdf.rb: -------------------------------------------------------------------------------- 1 | require 'nokogiri' 2 | 3 | module Nguyen 4 | class Xfdf 5 | 6 | attr_reader :options 7 | 8 | def initialize(fields = {}, options = {}) 9 | @fields = fields 10 | @options = { 11 | file: nil, 12 | id: nil 13 | }.merge(options) 14 | end 15 | 16 | # generate XFDF content 17 | def to_xfdf 18 | builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| 19 | xml.xfdf('xmlns' => 'http://ns.adobe.com/xfdf/', 'xml:space' => 'preserve') { 20 | xml.f(href: options[:file]) if options[:file] 21 | xml.ids(original: options[:id], modified: options[:id]) if options[:id] 22 | xml.fields { 23 | @fields.each do |field, value| 24 | xml.field(name: field) { 25 | if value.is_a? Array 26 | value.each { |item| xml.value(item.to_s) } 27 | else 28 | xml.value(value.to_s) 29 | end 30 | } 31 | end 32 | } 33 | } 34 | end 35 | builder.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML) 36 | end 37 | 38 | # write fdf content to path 39 | def save_to(path) 40 | File.write(path, to_xfdf) 41 | end 42 | 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /nguyen.gemspec: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | $:.push File.expand_path('../lib', __FILE__) 3 | require 'nguyen/version' 4 | 5 | Gem::Specification.new do |s| 6 | s.platform = Gem::Platform::RUBY 7 | s.name = 'nguyen' 8 | s.version = Nguyen::VERSION.dup 9 | s.summary = 'Fill out PDF forms by XFDF/FDF via pdftk.' 10 | s.description = 'Forms for Nguyên is Ruby library that could merge PDF fields by XFDF/FDF via pdftk.' 11 | 12 | s.authors = 'Trung Lê' 13 | s.email = 'trung.le@ruby-journal.com' 14 | s.homepage = 'http://github.com/ruby-journal/nguyen' 15 | s.license = %q{MIT} 16 | 17 | s.files = Dir['{lib}/**/*.rb', 'LICENSE', '*.md'] 18 | s.require_path = 'lib' 19 | s.requirements << 'pdtk 1.44.1 or newer' 20 | s.required_ruby_version = '>= 2.5.0' 21 | 22 | s.add_runtime_dependency 'nokogiri', '~> 1.10' 23 | s.add_development_dependency 'minitest' 24 | end 25 | -------------------------------------------------------------------------------- /test/fdf_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | describe Nguyen::Fdf do 4 | describe '#to_fdf' do 5 | let(:fdf) { Nguyen::Fdf.new field1: 'fieldvalue1', other_field: 'some other value' } 6 | 7 | it 'generates fdf' do 8 | assert fdf_text = fdf.to_fdf 9 | assert_match %r{<>}, fdf_text 10 | assert_match %r{<>}, fdf_text 11 | end 12 | 13 | describe 'hash value has quotes' do 14 | let(:quote_fdf) { Nguyen::Fdf.new field1: 'field(va)lue1' } 15 | it 'generates correct escaped quotes fdf' do 16 | assert_match '<>', quote_fdf.to_fdf 17 | end 18 | end 19 | 20 | describe 'hash value has multiple values' do 21 | let(:multi_values_fdf) { Nguyen::Fdf.new field1: %w(one two) } 22 | it 'generates correct escaped quotes fdf' do 23 | assert_match '<>', multi_values_fdf.to_fdf 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /test/fixtures/form.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-journal/nguyen/af4a22e3cf893956da3381f5f31dcc7d93554ade/test/fixtures/form.pdf -------------------------------------------------------------------------------- /test/pdf_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | describe Nguyen::Pdf do 4 | let(:pdftk) { Nguyen::PdftkWrapper.new 'pdftk' } 5 | 6 | describe '#fields' do 7 | let(:pdf) { Nguyen::Pdf.new 'test/fixtures/form.pdf', pdftk } 8 | it 'returns extracted fields from PDF' do 9 | fields = pdf.fields 10 | fields.any?.must_equal true 11 | fields.must_include 'program_name' 12 | end 13 | end 14 | 15 | describe '#new' do 16 | it 'reaise IOError if cannot read PDF file' do 17 | proc { Nguyen::Pdf.new 'foo/bar.pdf', pdftk }.must_raise IOError 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /test/pdftk_wrapper_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | describe Nguyen::PdftkWrapper do 4 | 5 | let(:pdftk) { Nguyen::PdftkWrapper.new('pdftk') } 6 | let(:pdftk_options) { Nguyen::PdftkWrapper.new('pdftk', flatten: true, encrypt: true) } 7 | 8 | describe '#get_field_names' do 9 | it 'returns fields name' do 10 | fields = pdftk.get_field_names 'test/fixtures/form.pdf' 11 | fields.must_include 'program_name' 12 | end 13 | end 14 | 15 | describe '#fill_form' do 16 | describe 'input file is FDF' do 17 | let(:fdf) { Nguyen::Fdf.new(quote_of_the_day: 'You are beautiful') } 18 | 19 | it 'fills the PDF' do 20 | pdftk.fill_form('test/fixtures/form.pdf', 'output.pdf', fdf) 21 | assert File.size('output.pdf') > 0 22 | FileUtils.rm('output.pdf') 23 | end 24 | end 25 | 26 | describe 'input file ix XFDF' do 27 | let(:xfdf) { Nguyen::Xfdf.new(quote_of_the_day: 'I love you') } 28 | 29 | it 'fills the PDF' do 30 | pdftk.fill_form('test/fixtures/form.pdf', 'output.pdf', xfdf) 31 | assert File.size('output.pdf') > 0 32 | FileUtils.rm('output.pdf') 33 | end 34 | end 35 | 36 | describe 'input file is xfdf xml string' do 37 | let(:xfdf) { Nguyen::Xfdf.new(quote_of_the_day: 'I love you').to_xfdf } 38 | 39 | it 'fills the PDF' do 40 | pdftk.fill_form('test/fixtures/form.pdf', 'output.pdf', xfdf) 41 | assert File.size('output.pdf') > 0 42 | FileUtils.rm('output.pdf') 43 | end 44 | end 45 | end 46 | 47 | describe '#cat' do 48 | 49 | before do 50 | FileUtils.cp('test/fixtures/form.pdf', 'test/fixtures/form2.pdf') 51 | end 52 | 53 | let(:pdf) { 'test/fixtures/form.pdf' } 54 | let(:pdf2) { 'test/fixtures/form2.pdf' } 55 | 56 | it 'combines pdfs' do 57 | pdftk.cat(pdf, pdf2, 'output.pdf') 58 | assert File.size('output.pdf') > File.size('test/fixtures/form.pdf') 59 | FileUtils.rm('output.pdf') 60 | end 61 | 62 | it 'allows a wildcard to combine pdfs' do 63 | pdftk.cat('test/fixtures/form*.pdf', 'output.pdf') 64 | assert File.size('output.pdf') > File.size('test/fixtures/form.pdf') 65 | FileUtils.rm('output.pdf') 66 | end 67 | 68 | after do 69 | FileUtils.rm('test/fixtures/form2.pdf') 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require_relative '../lib/nguyen' 2 | require 'pp' 3 | require 'minitest/autorun' 4 | -------------------------------------------------------------------------------- /test/xfdf_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | describe Nguyen::Xfdf do 4 | let(:xfdf) { Nguyen::Xfdf.new(field1: 'fieldvalue1', other_field: 'some other value') } 5 | 6 | it 'generates XFDF' do 7 | xfdf_text = xfdf.to_xfdf 8 | assert_match /.*(fieldvalue1)<\/value>.*<\/field>/m, xfdf_text 9 | assert_match /.*(some other value)<\/value>.*<\/field>/m, xfdf_text 10 | end 11 | end 12 | --------------------------------------------------------------------------------