Class: ApiHammer::Body

Inherits:
Object show all
Defined in:
lib/api_hammer/body.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(body, content_type) ⇒ Body

Returns a new instance of Body.



7
8
9
10
# File 'lib/api_hammer/body.rb', line 7

def initialize(body, content_type)
  @body = body
  @content_type = content_type
end

Instance Attribute Details

#bodyObject (readonly)

Returns the value of attribute body.



5
6
7
# File 'lib/api_hammer/body.rb', line 5

def body
  @body
end

#content_typeObject (readonly)

Returns the value of attribute content_type.



5
6
7
# File 'lib/api_hammer/body.rb', line 5

def content_type
  @content_type
end

Instance Method Details

#content_type_attrsObject



39
40
41
# File 'lib/api_hammer/body.rb', line 39

def content_type_attrs
  @content_type_attrs ||= ContentTypeAttrs.new(content_type)
end

#filtered(options) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/api_hammer/body.rb', line 23

def filtered(options)
  @filtered ||= Body.new(begin
    if media_type == 'application/json'
      begin
        ApiHammer::Filtration::Json.new(body, options).filter
      rescue JSON::ParserError
        body
      end
    elsif media_type == 'application/x-www-form-urlencoded'
      ApiHammer::Filtration::FormEncoded.new(body, options).filter
    else
      body
    end
  end, content_type)
end

#jsonifiableObject

deal with the vagaries of getting the response body in a form which JSON gem will not cry about generating



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/api_hammer/body.rb', line 49

def jsonifiable
  @jsonifiable ||= Body.new(catch(:jsonifiable) do
    original_body = self.body
    unless original_body.is_a?(String)
      begin
        # if the response body is not a string, but JSON doesn't complain 
        # about dumping whatever it is, go ahead and use it
        JSON.generate([original_body])
        throw :jsonifiable, original_body
      rescue
        # otherwise return nil - don't know what to do with whatever this object is 
        throw :jsonifiable, nil
      end
    end

    # first try to change the string's encoding per the Content-Type header 
    body = original_body.dup
    unless body.valid_encoding?
      # I think this always comes in as ASCII-8BIT anyway so may never get here. hopefully.
      body.force_encoding('ASCII-8BIT')
    end

    content_type_attrs = ContentTypeAttrs.new(content_type)
    if content_type_attrs.parsed?
      charset = content_type_attrs['charset'].first
      if charset && Encoding.list.any? { |enc| enc.to_s.downcase == charset.downcase }
        if body.dup.force_encoding(charset).valid_encoding?
          body.force_encoding(charset)
        else
          # I guess just ignore the specified encoding if the result is not valid. fall back to 
          # something else below.
        end
      end
    end
    begin
      JSON.generate([body])
    rescue Encoding::UndefinedConversionError, JSON::GeneratorError
      # if updating by content-type didn't do it, try UTF8 since JSON wants that - but only 
      # if it seems to be valid utf8. 
      # don't try utf8 if the response content-type indicated something else. 
      try_utf8 = !(content_type_attrs && content_type_attrs.parsed? && content_type_attrs['charset'].any? { |cs| !['utf8', ''].include?(cs.downcase) })
      if try_utf8 && body.dup.force_encoding('UTF-8').valid_encoding?
        body.force_encoding('UTF-8')
      else
        # I'm not sure if there is a way in this situation to get JSON gem to generate the 
        # string correctly. fall back to an array of codepoints I guess? this is a weird 
        # solution but the best I've got for now. 
        body = body.codepoints.to_a
      end
    end
    body
  end, content_type)
end

#media_typeObject



43
44
45
# File 'lib/api_hammer/body.rb', line 43

def media_type
  content_type_attrs.media_type
end

#objectObject

parses the body to an object



13
14
15
16
17
18
19
20
21
# File 'lib/api_hammer/body.rb', line 13

def object
  instance_variable_defined?(:@object) ? @object : @object = begin
    if media_type == 'application/json'
      JSON.parse(body) rescue nil
    elsif media_type == 'application/x-www-form-urlencoded'
      CGI.parse(body).map { |k, vs| {k => vs.last} }.inject({}, &:update)
    end
  end
end