usps_flags 0.5.0 → 0.5.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +22 -11
  3. data/.travis.yml +1 -1
  4. data/Gemfile.lock +5 -2
  5. data/README.md +6 -0
  6. data/lib/usps_flags.rb +35 -44
  7. data/lib/usps_flags/config.rb +89 -87
  8. data/lib/usps_flags/core.rb +44 -42
  9. data/lib/usps_flags/core/ensign.rb +53 -49
  10. data/lib/usps_flags/core/field.rb +96 -92
  11. data/lib/usps_flags/core/footer.rb +9 -5
  12. data/lib/usps_flags/core/headers.rb +58 -48
  13. data/lib/usps_flags/core/icons.rb +11 -7
  14. data/lib/usps_flags/core/icons/anchor.rb +62 -56
  15. data/lib/usps_flags/core/icons/binoculars.rb +21 -15
  16. data/lib/usps_flags/core/icons/lighthouse.rb +28 -22
  17. data/lib/usps_flags/core/icons/star.rb +21 -15
  18. data/lib/usps_flags/core/icons/trident.rb +136 -127
  19. data/lib/usps_flags/core/icons/trident_parts/hashes.rb +62 -55
  20. data/lib/usps_flags/core/icons/trumpet.rb +34 -28
  21. data/lib/usps_flags/core/pennant.rb +50 -46
  22. data/lib/usps_flags/core/trident_spec.rb +135 -131
  23. data/lib/usps_flags/core/trident_specs.rb +11 -7
  24. data/lib/usps_flags/core/trident_specs/base.rb +36 -26
  25. data/lib/usps_flags/core/trident_specs/circle.rb +36 -30
  26. data/lib/usps_flags/core/trident_specs/delta.rb +41 -30
  27. data/lib/usps_flags/core/trident_specs/header.rb +56 -50
  28. data/lib/usps_flags/core/trident_specs/horizontal.rb +80 -0
  29. data/lib/usps_flags/core/trident_specs/long.rb +41 -25
  30. data/lib/usps_flags/core/trident_specs/overlay.rb +40 -0
  31. data/lib/usps_flags/core/trident_specs/short.rb +30 -156
  32. data/lib/usps_flags/core/trident_specs/vertical.rb +108 -0
  33. data/lib/usps_flags/core/tridents.rb +54 -50
  34. data/lib/usps_flags/core/us.rb +40 -44
  35. data/lib/usps_flags/core/wheel.rb +7 -3
  36. data/lib/usps_flags/errors.rb +25 -23
  37. data/lib/usps_flags/generate.rb +111 -107
  38. data/lib/usps_flags/generate/flag.rb +160 -157
  39. data/lib/usps_flags/generate/generator_methods.rb +139 -0
  40. data/lib/usps_flags/generate/helper_methods.rb +88 -0
  41. data/lib/usps_flags/helpers.rb +163 -165
  42. data/lib/usps_flags/helpers/builders.rb +92 -85
  43. data/lib/usps_flags/helpers/spec_arrows.rb +127 -123
  44. data/lib/usps_flags/helpers/valid_flags.rb +45 -41
  45. data/lib/usps_flags/rational.rb +35 -0
  46. data/spec/usps_flags/config_spec.rb +17 -10
  47. data/spec/usps_flags/core_spec.rb +31 -31
  48. data/spec/usps_flags/generate_spec.rb +76 -73
  49. data/spec/usps_flags/helpers_spec.rb +8 -8
  50. data/spec/usps_flags/rational_spec.rb +17 -0
  51. data/spec/usps_flags_spec.rb +19 -21
  52. data/usps_flags.gemspec +7 -6
  53. metadata +34 -10
  54. data/lib/rational.rb +0 -39
  55. data/lib/usps_flags/generate/private.rb +0 -199
  56. data/spec/rational_spec.rb +0 -19
@@ -4,61 +4,57 @@
4
4
  #
5
5
  # This class should never need to be called directly.
6
6
  # @private
7
- class USPSFlags::Core::US
8
- def svg
9
- @base_hoist = 2000.to_f
10
- @base_fly = @base_hoist * 1.91
7
+ class USPSFlags
8
+ class Core
9
+ class US
10
+ def svg
11
+ @base_hoist = 2000.to_f
12
+ @base_fly = @base_hoist * 1.91
11
13
 
12
- @canton_hoist = @base_hoist * 7 / 13
13
- @canton_fly = @canton_hoist * Math.sqrt(2)
14
+ @canton_hoist = @base_hoist * 7 / 13
15
+ @canton_fly = @canton_hoist * Math.sqrt(2)
14
16
 
15
- @star_offset = 20 # Half of scaled star height
17
+ @star_offset = 20 # Half of scaled star height
16
18
 
17
- svg = defs
18
- svg << stripes
19
- svg << stars
19
+ defs + stripes + stars
20
+ end
20
21
 
21
- # star_diameter = base_hoist*4/5/13
22
- # svg << <<~SVG
23
- # <circle cx="#{@canton_fly*6/12}" cy="#{@canton_hoist*4/10-5}" r="#{star_diameter/2}" fill="#999999" fill-opacity="0.4" />
24
- # SVG
22
+ private
25
23
 
26
- svg
27
- end
24
+ def defs
25
+ File.read("#{File.dirname(__dir__)}/core/us_defs.svg.partial").gsub('STAR', USPSFlags::Core.star)
26
+ end
28
27
 
29
- private
28
+ def stars
29
+ rows = { odd: (1..9).step(2).to_a, even: (2..8).step(2).to_a }
30
+ columns = { odd: (1..11).step(2).to_a, even: (2..10).step(2).to_a }
30
31
 
31
- def defs
32
- File.read("#{File.dirname(__dir__)}/core/us_defs.svg.partial").gsub('STAR', USPSFlags::Core.star)
33
- end
32
+ svg = +''
33
+ %i[odd even].each { |type| svg << star_set(rows, columns, type) }
34
+ svg
35
+ end
34
36
 
35
- def stars
36
- rows = { odd: (1..9).step(2).to_a, even: (2..8).step(2).to_a }
37
- columns = { odd: (1..11).step(2).to_a, even: (2..10).step(2).to_a }
37
+ def star_set(rows, columns, type)
38
+ svg = +''
39
+ rows[type].each do |r|
40
+ columns[type].each do |c|
41
+ svg << <<~SVG
42
+ <g transform="translate(#{@canton_fly * c / 12}, #{@star_offset + @canton_hoist * r / 10})"><g><use href="#star" /></g></g>
43
+ SVG
44
+ end
45
+ end
46
+ svg
47
+ end
38
48
 
39
- svg = +''
40
- %i[odd even].each { |type| svg << star_set(rows, columns, type) }
41
- svg
42
- end
49
+ def stripes
50
+ s = (0..12).map do |i|
51
+ color = i.even? ? 'red' : 'white'
52
+ "<use href=\"##{color}-stripe\" y=\"#{@base_hoist * i / 13}\" />"
53
+ end
43
54
 
44
- def star_set(rows, columns, type)
45
- svg = +''
46
- rows[type].each do |r|
47
- columns[type].each do |c|
48
- svg << <<~SVG
49
- <g transform="translate(#{@canton_fly * c / 12}, #{@star_offset + @canton_hoist * r / 10})"><g><use href="#star" /></g></g>
50
- SVG
55
+ s.join("\n") + "\n<rect y=\"0\" width=\"#{@canton_fly}\" height=\"#{@canton_hoist}\" " \
56
+ "fill=\"#{USPSFlags::Config::OLD_GLORY_BLUE}\" />\n"
51
57
  end
52
58
  end
53
- svg
54
- end
55
-
56
- def stripes
57
- s = (0..12).map do |i|
58
- color = i.even? ? 'red' : 'white'
59
- "<use href=\"##{color}-stripe\" y=\"#{@base_hoist * i / 13}\" />"
60
- end
61
-
62
- s.join("\n") + "\n<rect y=\"0\" width=\"#{@canton_fly}\" height=\"#{@canton_hoist}\" fill=\"#{USPSFlags::Config::OLD_GLORY_BLUE}\" />\n"
63
59
  end
64
60
  end
@@ -4,8 +4,12 @@
4
4
  #
5
5
  # This class should never need to be called directly.
6
6
  # @private
7
- class USPSFlags::Core::Wheel
8
- def svg
9
- File.read("#{File.dirname(__dir__)}/core/wheel.svg.partial")
7
+ class USPSFlags
8
+ class Core
9
+ class Wheel
10
+ def svg
11
+ File.read("#{File.dirname(__dir__)}/core/wheel.svg.partial")
12
+ end
13
+ end
10
14
  end
11
15
  end
@@ -3,38 +3,40 @@
3
3
  # Custom errors.
4
4
  #
5
5
  # @private
6
- module USPSFlags::Errors
7
- class PNGGenerationError < StandardError
8
- attr_reader :svg
6
+ class USPSFlags
7
+ class Errors
8
+ class PNGGenerationError < StandardError
9
+ attr_reader :svg
9
10
 
10
- def initialize(msg = 'There was an error generating the PNG file.', svg: '')
11
- super(msg)
12
- @svg = svg
11
+ def initialize(msg = 'There was an error generating the PNG file.', svg: '')
12
+ super(msg)
13
+ @svg = svg
14
+ end
13
15
  end
14
- end
15
16
 
16
- class PNGConversionError < StandardError
17
- def initialize(msg = 'There was an error converting the PNG file.')
18
- super(msg)
17
+ class PNGConversionError < StandardError
18
+ def initialize(msg = 'There was an error converting the PNG file.')
19
+ super(msg)
20
+ end
19
21
  end
20
- end
21
22
 
22
- class StaticFilesGenerationError < StandardError
23
- attr_reader :cause
23
+ class StaticFilesGenerationError < StandardError
24
+ attr_reader :cause
24
25
 
25
- def initialize(msg = 'There was an error generating the static files.', cause: nil)
26
- super(msg)
27
- @cause = cause
26
+ def initialize(msg = 'There was an error generating the static files.', cause: nil)
27
+ super(msg)
28
+ @cause = cause
29
+ end
28
30
  end
29
- end
30
31
 
31
- class ZipGenerationError < StandardError
32
- attr_reader :type, :cause
32
+ class ZipGenerationError < StandardError
33
+ attr_reader :type, :cause
33
34
 
34
- def initialize(msg = 'There was an error generating the zip file.', type: nil, cause: nil)
35
- super(msg)
36
- @type = type
37
- @cause = cause
35
+ def initialize(msg = 'There was an error generating the zip file.', type: nil, cause: nil)
36
+ super(msg)
37
+ @type = type
38
+ @cause = cause
39
+ end
38
40
  end
39
41
  end
40
42
  end
@@ -1,127 +1,131 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  # Controller class for generating files.
4
- class USPSFlags::Generate
5
- require 'usps_flags/generate/private'
6
-
7
- class << self
8
- include USPSFlags::Generate::Private
9
- # The primary controller method. Generates an SVG file or SVG data.
10
- #
11
- # @param [String] flag The flag type to generate.
12
- # @param [String] outfile The path to save the SVG file to. If not set, prints to console.
13
- # @param [Boolean] field Whether to generate the flag field (including any border).
14
- # @param [String] scale The image scale divisor factor.
15
- # @return [String] Returns the SVG data.
16
- def svg(flag, outfile: nil, scale: nil, field: true)
17
- flag = flag.upcase.delete('/', '_', 'PENNANT')
18
-
19
- USPSFlags::Helpers.ensure_dir_for_file(outfile)
20
-
21
- output = special_flag(flag, outfile, scale)
22
- output ||= USPSFlags::Generate::Flag.officer(rank: flag, outfile: outfile, scale: scale, field: field)
23
- output
24
- end
25
-
26
- # Convert SVG data into a PNG file.
27
- #
28
- # @param [String] svg The SVG data.
29
- # @param [String] outfile The path to save the PNG file to. (Required because the file is not accessible if this is left blank.)
30
- # @param [Boolean] trim Whether to trim the generated PNG file of excess transparency.
31
- # @param [String] background Background color. Defaults to 'none' (transparent).
32
- def png(svg, outfile: nil, trim: false, background: 'none')
33
- raise USPSFlags::Errors::PNGGenerationError.new(svg: svg) if outfile.nil? || outfile.empty?
4
+ class USPSFlags
5
+ class Generate
6
+ require 'usps_flags/generate/helper_methods'
7
+ require 'usps_flags/generate/generator_methods'
8
+
9
+ class << self
10
+ include USPSFlags::Generate::HelperMethods
11
+ include USPSFlags::Generate::GeneratorMethods
12
+ # The primary controller method. Generates an SVG file or SVG data.
13
+ #
14
+ # @param [String] flag The flag type to generate.
15
+ # @param [String] outfile The path to save the SVG file to. If not set, prints to console.
16
+ # @param [Boolean] field Whether to generate the flag field (including any border).
17
+ # @param [String] scale The image scale divisor factor.
18
+ # @return [String] Returns the SVG data.
19
+ def svg(flag, outfile: nil, scale: nil, field: true)
20
+ flag = flag.upcase.delete('/', '_', 'PENNANT')
21
+
22
+ USPSFlags::Helpers.ensure_dir_for_file(outfile)
23
+
24
+ output = special_flag(flag, outfile, scale)
25
+ output ||= USPSFlags::Generate::Flag.officer(rank: flag, outfile: outfile, scale: scale, field: field)
26
+ output
27
+ end
34
28
 
35
- set_temp_svg(svg)
29
+ # Convert SVG data into a PNG file.
30
+ #
31
+ # @param [String] svg The SVG data.
32
+ # @param [String] outfile The path to save the PNG file to. (Required because the file isn't accessible if blank.)
33
+ # @param [Boolean] trim Whether to trim the generated PNG file of excess transparency.
34
+ # @param [String] background Background color. Defaults to 'none' (transparent).
35
+ def png(svg, outfile: nil, trim: false, background: 'none')
36
+ raise USPSFlags::Errors::PNGGenerationError.new(svg: svg) if outfile.nil? || outfile.empty?
36
37
 
37
- USPSFlags::Helpers.ensure_dir_for_file(outfile)
38
+ set_temp_svg(svg)
38
39
 
39
- generate_png(background, trim, outfile)
40
- ensure
41
- ::File.delete(@temp_svg_path) if delete_temp_svg?
42
- end
40
+ USPSFlags::Helpers.ensure_dir_for_file(outfile)
43
41
 
44
- # Generate all static SVG and PNG files, and automaticall generates zip archives for download.
45
- #
46
- # @param [Boolean] svg Whether to generate SVG images.
47
- # @param [Boolean] png Whether to generate PNG images.
48
- # @param [Boolean] zips Whether to create zip archives for all images created. Does not create a zip for skipped formats.
49
- # @param [Boolean] reset Whether to delete all previous files before generating new files.
50
- def all(svg: true, png: true, zips: true, reset: true)
51
- all_arg_error unless any_all_arg?(svg, png, zips, reset)
52
-
53
- track_time do
54
- remove_static_files if reset
55
- images(svg: svg, png: png) if svg || png
56
- zips(svg: svg, png: png) if zips
42
+ generate_png(background, trim, outfile)
43
+ ensure
44
+ ::File.delete(@temp_svg_path) if delete_temp_svg?
57
45
  end
58
- end
59
46
 
60
- # Generate zip archives of current static image files.
61
- #
62
- # @param [Boolean] svg Generate zip archive of SVG images.
63
- # @param [Boolean] png Generate zip archive of PNG images.
64
- def zips(svg: true, png: true)
65
- unless svg || png
66
- raise(
67
- USPSFlags::Errors::ZipGenerationError,
68
- 'At least one argument switch must be true out of [svg, png].'
69
- )
47
+ # Generate all static SVG and PNG files, and automaticall generates zip archives for download.
48
+ #
49
+ # @param [Boolean] svg Whether to generate SVG images.
50
+ # @param [Boolean] png Whether to generate PNG images.
51
+ # @param [Boolean] zips Whether to create zip archives for all images created.
52
+ # @param [Boolean] reset Whether to delete all previous files before generating new files.
53
+ def all(svg: true, png: true, zips: true, reset: true)
54
+ all_arg_error unless any_all_arg?(svg, png, zips, reset)
55
+
56
+ track_time do
57
+ remove_static_files if reset
58
+ images(svg: svg, png: png) if svg || png
59
+ zips(svg: svg, png: png) if zips
60
+ end
70
61
  end
71
62
 
72
- generate_zip('svg') if svg
73
- generate_zip('png') if png
74
- end
63
+ # Generate zip archives of current static image files.
64
+ #
65
+ # @param [Boolean] svg Generate zip archive of SVG images.
66
+ # @param [Boolean] png Generate zip archive of PNG images.
67
+ def zips(svg: true, png: true)
68
+ unless svg || png
69
+ raise(
70
+ USPSFlags::Errors::ZipGenerationError,
71
+ 'At least one argument switch must be true out of [svg, png].'
72
+ )
73
+ end
74
+
75
+ generate_zip('svg') if svg
76
+ generate_zip('png') if png
77
+ end
75
78
 
76
- # Generate static image files.
77
- #
78
- # @param [Boolean] svg Generate static SVG images.
79
- # @param [Boolean] png Generate static PNG images.
80
- def images(svg: true, png: true)
81
- static_generation_header
82
- USPSFlags::Helpers.valid_flags(:all).each do |flag|
83
- generate_static_images_for(flag, svg: svg, png: png)
79
+ # Generate static image files.
80
+ #
81
+ # @param [Boolean] svg Generate static SVG images.
82
+ # @param [Boolean] png Generate static PNG images.
83
+ def images(svg: true, png: true)
84
+ static_generation_header
85
+ USPSFlags::Helpers.valid_flags(:all).each do |flag|
86
+ generate_static_images_for(flag, svg: svg, png: png)
87
+ end
84
88
  end
85
- end
86
89
 
87
- # Generate trident spec sheet as an SVG image.
88
- #
89
- # @param [String] outfile The path to save the SVG file to. If not set, prints to console.
90
- # @param [Integer] fly The nominal fly length of an appropriate flag field for the generated tridents. Size labels scale to this size.
91
- # @param [String] outfile The unit to append to all trident measurements.
92
- # @param [String] scale The image scale divisor factor.
93
- # @return [String] Returns the SVG data.
94
- def spec(outfile: nil, fly: USPSFlags::Config::BASE_FLY, unit: nil, scale: nil, scaled_border: false)
95
- svg = +''
96
- svg << USPSFlags::Core.headers(scale: scale, title: 'USPS Trident Specifications')
97
- svg << USPSFlags::Core.trident_spec(fly: fly, unit: unit, scaled_border: scaled_border)
98
- svg << USPSFlags::Core.footer
99
-
100
- USPSFlags::Helpers.output(svg, outfile: outfile)
101
- end
90
+ # Generate trident spec sheet as an SVG image.
91
+ #
92
+ # @param [String] outfile The path to save the SVG file to. If not set, prints to console.
93
+ # @param [Integer] fly The nominal fly length of an appropriate flag field for the generated tridents.
94
+ # @param [String] outfile The unit to append to all trident measurements.
95
+ # @param [String] scale The image scale divisor factor.
96
+ # @return [String] Returns the SVG data.
97
+ def spec(outfile: nil, fly: USPSFlags::Config::BASE_FLY, unit: nil, scale: nil, scaled_border: false)
98
+ svg = +''
99
+ svg << USPSFlags::Core.headers(scale: scale, title: 'USPS Trident Specifications')
100
+ svg << USPSFlags::Core.trident_spec(fly: fly, unit: unit, scaled_border: scaled_border)
101
+ svg << USPSFlags::Core.footer
102
+
103
+ USPSFlags::Helpers.output(svg, outfile: outfile)
104
+ end
102
105
 
103
- private
104
-
105
- def special_flag(flag, outfile, scale)
106
- case flag
107
- when 'CRUISE', 'OIC'
108
- USPSFlags::Generate::Flag.pennant(type: flag, outfile: outfile, scale: scale)
109
- when 'ENSIGN'
110
- USPSFlags::Generate::Flag.ensign(outfile: outfile, scale: scale)
111
- when 'US'
112
- USPSFlags::Generate::Flag.us(outfile: outfile, scale: scale)
113
- when 'WHEEL'
114
- USPSFlags::Generate::Flag.wheel(outfile: outfile, scale: scale)
106
+ private
107
+
108
+ def special_flag(flag, outfile, scale)
109
+ case flag
110
+ when 'CRUISE', 'OIC'
111
+ USPSFlags::Generate::Flag.pennant(type: flag, outfile: outfile, scale: scale)
112
+ when 'ENSIGN'
113
+ USPSFlags::Generate::Flag.ensign(outfile: outfile, scale: scale)
114
+ when 'US'
115
+ USPSFlags::Generate::Flag.us(outfile: outfile, scale: scale)
116
+ when 'WHEEL'
117
+ USPSFlags::Generate::Flag.wheel(outfile: outfile, scale: scale)
118
+ end
115
119
  end
116
- end
117
120
 
118
- def generate_png(background, trim, outfile)
119
- MiniMagick::Tool::Convert.new do |convert|
120
- convert << '-background' << background
121
- convert << '-format' << 'png'
122
- convert << '-trim' if trim
123
- convert << @temp_svg_path
124
- convert << outfile
121
+ def generate_png(background, trim, outfile)
122
+ MiniMagick::Tool::Convert.new do |convert|
123
+ convert << '-background' << background
124
+ convert << '-format' << 'png'
125
+ convert << '-trim' if trim
126
+ convert << @temp_svg_path
127
+ convert << outfile
128
+ end
125
129
  end
126
130
  end
127
131
  end
@@ -4,164 +4,167 @@
4
4
  #
5
5
  # These methods should never need to be called directly.
6
6
  # @private
7
- class USPSFlags::Generate::Flag
8
- class << self
9
- def officer(rank: nil, outfile: nil, scale: nil, field: true)
10
- raise ArgumentError, 'No rank specified.' if rank.nil?
11
-
12
- @rank = rank.to_s.upcase
13
- @field = field
14
-
15
- svg = +''
16
- svg << USPSFlags::Core.headers(scale: scale, title: @rank)
17
- modify_rank_for_insignia
18
- @flag_details = USPSFlags::Helpers.flag_details(@rank)
19
- @trident_color = @field ? :white : @flag_details[:color]
20
- svg << officer_flag_body(@flag_details[:style])
21
-
22
- USPSFlags::Helpers.output(svg, outfile: outfile)
23
- end
24
-
25
- def special(type, level:, field: true)
26
- # Paths were designed for a base fly of 3000 pixels, but the base was changed for more useful fractions.
27
- svg = +''
28
- svg << "<g transform=\"translate(#{USPSFlags::Config::BASE_FLY / 10})\">" unless field
29
- svg << "<g transform=\"scale(#{Rational(USPSFlags::Config::BASE_FLY, 3000).to_f})\">"
30
- svg << special_icon(type, level)
31
- svg << '</g>'
32
- svg << '</g>' unless field
33
-
34
- svg
35
- end
36
-
37
- def pennant(type: 'CRUISE', outfile: nil, scale: nil)
38
- type = type.upcase
39
- svg = +''
40
- title = { 'CRUISE' => 'Cruise Pennant', 'OIC' => 'Officer-in-Charge Pennant' }[type]
41
- svg << USPSFlags::Core.headers(pennant: true, scale: scale, title: title)
42
- svg << USPSFlags::Core.pennant(type)
43
- svg << USPSFlags::Core.footer
44
-
45
- USPSFlags::Helpers.output(svg, outfile: outfile)
46
- end
47
-
48
- def ensign(outfile: nil, scale: nil)
49
- svg = +''
50
- svg << USPSFlags::Core.headers(scale: scale, title: 'USPS Ensign')
51
- svg << USPSFlags::Core.ensign
52
- svg << USPSFlags::Core.footer
53
-
54
- USPSFlags::Helpers.output(svg, outfile: outfile)
55
- end
56
-
57
- def wheel(outfile: nil, scale: nil)
58
- width = 4327.4667
59
- height = 4286.9333
60
- svg = +''
61
- svg << USPSFlags::Core.headers(width: width, height: height, scale: scale, title: 'USPS Ensign Wheel')
62
- svg << USPSFlags::Core.wheel
63
- svg << USPSFlags::Core.footer
64
-
65
- USPSFlags::Helpers.output(svg, outfile: outfile)
66
- end
67
-
68
- def us(outfile: nil, scale: nil)
69
- base_hoist = 2000.to_f
70
- hoist = scale.nil? ? base_hoist : (base_hoist / scale)
71
- fly = hoist * 1.91
72
- svg = +''
73
- svg << USPSFlags::Core.headers(width: fly, height: hoist, scale: scale, title: 'US Ensign')
74
- svg << USPSFlags::Core.us
75
- svg << USPSFlags::Core.footer
76
-
77
- USPSFlags::Helpers.output(svg, outfile: outfile)
78
- end
79
-
80
- private
81
-
82
- def special_icon(type, level)
83
- {
84
- a: USPSFlags::Core.binoculars(level), f: USPSFlags::Core.trumpet(level),
85
- fc: USPSFlags::Core.anchor, pc: USPSFlags::Core.lighthouse
86
- }[type]
87
- end
88
-
89
- def get_officer_flag
90
- [
91
- get_national_bridge_flag, get_bridge_flag, get_offset_flag, get_special_flag
92
- ].compact.first || get_trident_flag
93
- end
94
-
95
- def get_national_bridge_flag
96
- return unless cc? || vc?
97
-
98
- return USPSFlags::Core::Tridents.cc(@flag_details[:type], trident_color: @trident_color) if cc?
99
- return USPSFlags::Core::Tridents.vc(@flag_details[:type], trident_color: @trident_color) if vc?
100
- end
101
-
102
- def get_bridge_flag
103
- return unless three? || two?
104
-
105
- if three?
106
- USPSFlags::Core::Tridents.three(@flag_details[:type], trident_color: @trident_color, field_color: @flag_details[:color])
107
- elsif two?
108
- USPSFlags::Core::Tridents.two(@flag_details[:type], trident_color: @trident_color, field_color: @flag_details[:color])
7
+ class USPSFlags
8
+ class Generate
9
+ class Flag
10
+ class << self
11
+ def officer(rank: nil, outfile: nil, scale: nil, field: true)
12
+ raise ArgumentError, 'No rank specified.' if rank.nil?
13
+
14
+ @rank = rank.to_s.upcase
15
+ @field = field
16
+
17
+ svg = USPSFlags::Core.headers(scale: scale, title: @rank)
18
+ modify_rank_for_insignia
19
+ @flag_details = USPSFlags::Helpers.flag_details(@rank)
20
+ @trident_color = @field ? :white : @flag_details[:color]
21
+ svg << officer_flag_body(@flag_details[:style])
22
+
23
+ USPSFlags::Helpers.output(svg, outfile: outfile)
24
+ end
25
+
26
+ def special(type, level:, field: true)
27
+ # Paths were designed for a base fly of 3000 pixels, but the base was changed for more useful fractions.
28
+ svg = +''
29
+ svg << "<g transform=\"translate(#{USPSFlags::Config::BASE_FLY / 10})\">" unless field
30
+ svg << "<g transform=\"scale(#{Rational(USPSFlags::Config::BASE_FLY, 3000).to_f})\">"
31
+ svg << special_icon(type, level)
32
+ svg << '</g>'
33
+ svg << '</g>' unless field
34
+
35
+ svg
36
+ end
37
+
38
+ def pennant(type: 'CRUISE', outfile: nil, scale: nil)
39
+ type = type.upcase
40
+ title = { 'CRUISE' => 'Cruise Pennant', 'OIC' => 'Officer-in-Charge Pennant' }[type]
41
+ svg = USPSFlags::Core.headers(pennant: true, scale: scale, title: title)
42
+ svg << USPSFlags::Core.pennant(type)
43
+ svg << USPSFlags::Core.footer
44
+
45
+ USPSFlags::Helpers.output(svg, outfile: outfile)
46
+ end
47
+
48
+ def ensign(outfile: nil, scale: nil)
49
+ svg = USPSFlags::Core.headers(scale: scale, title: 'USPS Ensign')
50
+ svg << USPSFlags::Core.ensign
51
+ svg << USPSFlags::Core.footer
52
+
53
+ USPSFlags::Helpers.output(svg, outfile: outfile)
54
+ end
55
+
56
+ def wheel(outfile: nil, scale: nil)
57
+ width = 4327.4667
58
+ height = 4286.9333
59
+ svg = USPSFlags::Core.headers(width: width, height: height, scale: scale, title: 'USPS Ensign Wheel')
60
+ svg << USPSFlags::Core.wheel
61
+ svg << USPSFlags::Core.footer
62
+
63
+ USPSFlags::Helpers.output(svg, outfile: outfile)
64
+ end
65
+
66
+ def us(outfile: nil, scale: nil)
67
+ base_hoist = 2000.to_f
68
+ hoist = scale.nil? ? base_hoist : (base_hoist / scale)
69
+ fly = hoist * 1.91
70
+ svg = USPSFlags::Core.headers(width: fly, height: hoist, scale: scale, title: 'US Ensign')
71
+ svg << USPSFlags::Core.us
72
+ svg << USPSFlags::Core.footer
73
+
74
+ USPSFlags::Helpers.output(svg, outfile: outfile)
75
+ end
76
+
77
+ private
78
+
79
+ def special_icon(type, level)
80
+ {
81
+ a: USPSFlags::Core.binoculars(level), f: USPSFlags::Core.trumpet(level),
82
+ fc: USPSFlags::Core.anchor, pc: USPSFlags::Core.lighthouse
83
+ }[type]
84
+ end
85
+
86
+ def get_officer_flag
87
+ [
88
+ get_national_bridge_flag, get_bridge_flag, get_offset_flag, get_special_flag
89
+ ].compact.first || get_trident_flag
90
+ end
91
+
92
+ def get_national_bridge_flag
93
+ return unless cc? || vc?
94
+
95
+ return USPSFlags::Core::Tridents.cc(@flag_details[:type], trident_color: @trident_color) if cc?
96
+ return USPSFlags::Core::Tridents.vc(@flag_details[:type], trident_color: @trident_color) if vc?
97
+ end
98
+
99
+ def get_bridge_flag
100
+ return unless three? || two?
101
+
102
+ if three?
103
+ USPSFlags::Core::Tridents.three(
104
+ @flag_details[:type], trident_color: @trident_color, field_color: @flag_details[:color]
105
+ )
106
+ elsif two?
107
+ USPSFlags::Core::Tridents.two(
108
+ @flag_details[:type], trident_color: @trident_color, field_color: @flag_details[:color]
109
+ )
110
+ end
111
+ end
112
+
113
+ def get_offset_flag
114
+ return unless offset?
115
+
116
+ USPSFlags::Core::Tridents.offset(@flag_details[:type], field_color: @flag_details[:color], field: @field)
117
+ end
118
+
119
+ def get_special_flag
120
+ return unless special?
121
+
122
+ special(@flag_details[:type], level: @flag_details[:level], field: @field)
123
+ end
124
+
125
+ def get_trident_flag
126
+ USPSFlags::Core.trident(@flag_details[:type], field_color: @flag_details[:color])
127
+ end
128
+
129
+ def officer_flag_body(style)
130
+ svg = +''
131
+ svg << USPSFlags::Core.field(style: style, color: @flag_details[:color]) if @field
132
+ svg << '<g transform="translate(-150, 400)"><g transform="scale(0.58333)">' if style == :past
133
+ svg << get_officer_flag
134
+ svg << '</g></g>' if style == :past
135
+ svg << USPSFlags::Core.footer
136
+ svg
137
+ end
138
+
139
+ def modify_rank_for_insignia
140
+ @rank.slice!(0) if !@field && USPSFlags::Helpers.valid_flags(:past).include?(@rank)
141
+ @rank = 'CDR' if @rank == 'C'
142
+ end
143
+
144
+ def cc?
145
+ @flag_details[:type] == :n && @flag_details[:count] == 3
146
+ end
147
+
148
+ def vc?
149
+ @flag_details[:type] == :n && @flag_details[:count] == 2
150
+ end
151
+
152
+ def three?
153
+ %i[s d].include?(@flag_details[:type]) && @flag_details[:count] == 3
154
+ end
155
+
156
+ def two?
157
+ %i[s d].include?(@flag_details[:type]) && @flag_details[:count] == 2
158
+ end
159
+
160
+ def offset?
161
+ %w[LT DLT].include?(@rank)
162
+ end
163
+
164
+ def special?
165
+ %i[a f fc pc].include?(@flag_details[:type])
166
+ end
109
167
  end
110
168
  end
111
-
112
- def get_offset_flag
113
- return unless offset?
114
-
115
- USPSFlags::Core::Tridents.offset(@flag_details[:type], field_color: @flag_details[:color], field: @field)
116
- end
117
-
118
- def get_special_flag
119
- return unless special?
120
-
121
- special(@flag_details[:type], level: @flag_details[:level], field: @field)
122
- end
123
-
124
- def get_trident_flag
125
- USPSFlags::Core.trident(@flag_details[:type], field_color: @flag_details[:color])
126
- end
127
-
128
- def officer_flag_body(style)
129
- svg = +''
130
- svg << USPSFlags::Core.field(style: style, color: @flag_details[:color]) if @field
131
- svg << '<g transform="translate(-150, 400)"><g transform="scale(0.58333)">' if style == :past
132
- svg << get_officer_flag
133
- svg << '</g></g>' if style == :past
134
- svg << USPSFlags::Core.footer
135
- svg
136
- end
137
-
138
- def modify_rank_for_insignia
139
- @rank.slice!(0) if !@field && USPSFlags::Helpers.valid_flags(:past).include?(@rank)
140
- @rank = 'CDR' if @rank == 'C'
141
- end
142
-
143
- def cc?
144
- @flag_details[:type] == :n && @flag_details[:count] == 3
145
- end
146
-
147
- def vc?
148
- @flag_details[:type] == :n && @flag_details[:count] == 2
149
- end
150
-
151
- def three?
152
- [:s, :d].include?(@flag_details[:type]) && @flag_details[:count] == 3
153
- end
154
-
155
- def two?
156
- [:s, :d].include?(@flag_details[:type]) && @flag_details[:count] == 2
157
- end
158
-
159
- def offset?
160
- %w[LT DLT].include?(@rank)
161
- end
162
-
163
- def special?
164
- [:a, :f, :fc, :pc].include?(@flag_details[:type])
165
- end
166
169
  end
167
170
  end