Class: TwelvedataRuby::Response

Inherits:
Object
  • Object
show all
Defined in:
lib/twelvedata_ruby/response.rb

Constant Summary collapse

CSV_COL_SEP =
";"
BODY_MAX_BYTESIZE =
16_000
HTTP_STATUSES =
{http_error: (400..600), success: (200..299)}.freeze
CONTENT_TYPE_HANDLERS =
{
  json: {parser: :json_parser, dumper: :json_dumper},
  csv: {parser: :csv_parser, dumper: :csv_dumper},
  plain: {parser: :plain_parser, dumper: :to_s}
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(http_response:, request:, headers: nil, body: nil) ⇒ Response

Returns a new instance of Response.



40
41
42
# File 'lib/twelvedata_ruby/response.rb', line 40

def initialize(http_response:, request:, headers: nil, body: nil)
  self.http_response = http_response
end

Instance Attribute Details

#body_bytesizeObject (readonly)

Returns the value of attribute body_bytesize.



38
39
40
# File 'lib/twelvedata_ruby/response.rb', line 38

def body_bytesize
  @body_bytesize
end

#headersObject

Returns the value of attribute headers.



38
39
40
# File 'lib/twelvedata_ruby/response.rb', line 38

def headers
  @headers
end

#http_responseObject

Returns the value of attribute http_response.



38
39
40
# File 'lib/twelvedata_ruby/response.rb', line 38

def http_response
  @http_response
end

#requestObject

Returns the value of attribute request.



38
39
40
# File 'lib/twelvedata_ruby/response.rb', line 38

def request
  @request
end

Class Method Details

.http_status_codesObject



33
34
35
# File 'lib/twelvedata_ruby/response.rb', line 33

def http_status_codes
  @http_status_codes ||= HTTP_STATUSES.values.map(&:to_a).flatten
end

.resolve(http_response, request) ⇒ Object



16
17
18
19
20
21
22
# File 'lib/twelvedata_ruby/response.rb', line 16

def resolve(http_response, request)
  if http_status_codes.member?(http_response.status)
    new(http_response: http_response, request: request)
  else
    resolve_error(http_response, request)
  end
end

.resolve_error(http_response, request) ⇒ Object



24
25
26
27
28
29
30
31
# File 'lib/twelvedata_ruby/response.rb', line 24

def resolve_error(http_response, request)
  error_attribs = if http_response.respond_to?(:error) && http_response.error
                    {message: http_response.error.message, code: http_response.error.class.name}
                  else
                    {message: http_response.body.to_s, code: http_response.status}
                  end
  TwelvedataRuby::ResponseError.new(json: (error_attribs || {}), request: request)
end

Instance Method Details

#attachment_filenameObject



44
45
46
47
48
# File 'lib/twelvedata_ruby/response.rb', line 44

def attachment_filename
  return nil unless headers["content-disposition"]

  @attachment_filename ||= headers["content-disposition"].split("filename=").last.delete("\"")
end

#body_parserObject



50
51
52
# File 'lib/twelvedata_ruby/response.rb', line 50

def body_parser
  CONTENT_TYPE_HANDLERS[content_type][:parser]
end

#content_typeObject



54
55
56
# File 'lib/twelvedata_ruby/response.rb', line 54

def content_type
  @content_type ||= headers["content-type"].match(%r{^.+/([a-z]+).*$})&.send(:[], 1)&.to_sym
end

#csv_dumperObject



62
63
64
# File 'lib/twelvedata_ruby/response.rb', line 62

def csv_dumper
  parsed_body.is_a?(CSV::Table) ? parsed_body.to_csv(col_sep: CSV_COL_SEP) : nil
end

#csv_parser(io) ⇒ Object



58
59
60
# File 'lib/twelvedata_ruby/response.rb', line 58

def csv_parser(io)
  CSV.parse(io, headers: true, col_sep: CSV_COL_SEP)
end

#dumped_parsed_bodyObject



66
67
68
69
# File 'lib/twelvedata_ruby/response.rb', line 66

def dumped_parsed_body
  @dumped_parsed_body ||=
    parsed_body.respond_to?(parsed_body_dumper) ? parsed_body.send(parsed_body_dumper) : send(parsed_body_dumper)
end

#errorObject



71
72
73
74
75
76
# File 'lib/twelvedata_ruby/response.rb', line 71

def error
  klass_name = ResponseError.error_code_klass(status_code, success_http_status? ? :api : :http)
  return unless klass_name
  TwelvedataRuby.const_get(klass_name)
    .new(json: parsed_body, request: request, code: status_code, message: parsed_body)
end

#http_status_codeObject



78
79
80
# File 'lib/twelvedata_ruby/response.rb', line 78

def http_status_code
  http_response&.status
end

#json_dumperObject



82
83
84
# File 'lib/twelvedata_ruby/response.rb', line 82

def json_dumper
  parsed_body.is_a?(Hash) ? JSON.dump(parsed_body) : nil
end

#json_parser(io) ⇒ Object



86
87
88
# File 'lib/twelvedata_ruby/response.rb', line 86

def json_parser(io)
  JSON.parse(io, symbolize_names: true)
end

#parsed_bodyObject Also known as: body, parse_http_response_body



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/twelvedata_ruby/response.rb', line 90

def parsed_body
  return @parsed_body if @parsed_body || http_response&.body.nil? || http_response&.body.closed?

  begin
    tmp_file = nil
    if body_bytesize < BODY_MAX_BYTESIZE
      @parsed_body = send(body_parser, http_response.body.to_s)
    else
      tmp_file = Tempfile.new
      http_response.body.copy_to(tmp_file)
      @parsed_body = send(body_parser, IO.read(tmp_file.path))
    end
  ensure
    http_response.body.close
    tmp_file&.close
    tmp_file&.unlink
  end

  @parsed_body
end

#parsed_body_dumperObject



113
114
115
# File 'lib/twelvedata_ruby/response.rb', line 113

def parsed_body_dumper
  CONTENT_TYPE_HANDLERS[content_type][:dumper]
end

#plain_parser(io = nil) ⇒ Object



117
118
119
# File 'lib/twelvedata_ruby/response.rb', line 117

def plain_parser(io=nil)
  io.to_s || http_response.body.to_s
end

#status_codeObject



121
122
123
# File 'lib/twelvedata_ruby/response.rb', line 121

def status_code
  @status_code ||= parsed_body.is_a?(Hash) ? parsed_body[:code] : http_status_code
end

#success_http_status?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/twelvedata_ruby/response.rb', line 125

def success_http_status?
  @success_http_status ||= HTTP_STATUSES[:success].member?(http_status_code) || false
end

#to_disk_file(file_fullpath = attachment_filename) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
# File 'lib/twelvedata_ruby/response.rb', line 129

def to_disk_file(file_fullpath=attachment_filename)
  return nil unless file_fullpath

  begin
    file = File.open(file_fullpath, "w")
    file.puts dumped_parsed_body
    file
  ensure
    file&.close
  end
end