Passed
Push — master ( e9b4be...fdfd44 )
by Paul
01:35
created

ContentParser.munge_hash_value()   B

Complexity

Conditions 6

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
dl 0
loc 17
ccs 8
cts 8
cp 1
crap 6
rs 8
c 2
b 0
f 0
1 1
require "json"
2 1
require "base64"
3 1
require_relative "file_fetcher"
4 1
require_relative "file_system"
5
6 1
module Resume
7 1
  module CLI
8 1
    module ContentParser
9 1
      ASSET_PATH = /dropbox/
10 1
      private_constant :ASSET_PATH
11
      # Regex taken from http://stackoverflow.com/q/8571501/567863
12 1
      BASE64_STRING_REGEX = %r{\A
13
        ([A-Za-z0-9+/]{4})*
14
        ([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)
15
      \z}x
16 1
      private_constant :BASE64_STRING_REGEX
17
18 1
      module_function
19
20 1
      def decode_content(string)
21
        # Force encoding to UTF-8 is needed for strings that had UTF-8
22
        # characters in them when they were originally encoded
23 200
        Base64.strict_decode64(string).force_encoding("utf-8")
24
      end
25
26 1
      def parse(resume)
27 11
        JSON.recurse_proc(resume, &decode_and_fetch_assets)
28
      end
29
30
      # Values that need parsing can be found in hash and array values
31
      # in the JSON, so specifically target those data types for
32
      # manipulation, and ignore any direct references given to the
33
      # keys or values of the JSON hash.
34 1
      def decode_and_fetch_assets
35 11
        proc do |object|
36 1241
          case object
37
          when Hash
38 127
            parse_hash(object)
39
          when Array
40 86
            parse_array(object)
41
          else
42 1028
            object
43
          end
44
        end
45
      end
46 1
      private_class_method :decode_and_fetch_assets
47
48 1
      def parse_hash(hash)
49 127
        hash.each do |key, value|
50 565
          if value =~ BASE64_STRING_REGEX
51 139
            value = decode_content(value)
52
          end
53 565
          if value =~ ASSET_PATH
54 26
            hash[key] = FileFetcher.fetch(value)
55 26
            next
56
          end
57 539
          munge_hash_value(hash, key, value)
58
        end
59
      end
60 1
      private_class_method :parse_hash
61
62 1
      def munge_hash_value(hash, key, value)
63 539
        if key == :align
64
          # Prawn specifically requires :align values to
65
          # be symbols otherwise it errors out
66 14
          hash[key] = value.to_sym
67 525
        elsif key == :styles && value.is_a?(Array)
68
          # Prawn specifically requires :styles values to
69
          # be symbols otherwise the styles do not take effect
70 51
          hash[key] = value.map!(&:to_sym)
71 474
        elsif key == :font && value.is_a?(Hash)
72
          # This is the hash that tells Prawn what the fonts to be used
73
          # are called and where they are located
74 2
          substitute_filenames_for_filepaths(value)
75
        else
76 472
          hash[key] = value
77
        end
78
      end
79 1
      private_class_method :munge_hash_value
80
81 1
      def substitute_filenames_for_filepaths(value)
82 2
        %i(normal bold).each do |property|
83 4
          if value.key?(property)
84 2
            value[property] = FileSystem.tmpfile_path(value[property])
85
          end
86
        end
87
      end
88 1
      private_class_method :substitute_filenames_for_filepaths
89
90 1
      def parse_array(array)
91 86
        array.each_with_index do |value, index|
92 100
          if value =~ BASE64_STRING_REGEX
93 57
            array[index] = decode_content(value)
94
          end
95
        end
96
      end
97 1
      private_class_method :parse_array
98
    end
99
  end
100
end
101