Class: Mudbug

Inherits:
Object
  • Object
show all
Extended by:
Lager
Defined in:
lib/mudbug.rb

Defined Under Namespace

Classes: ContentTypeError, StatusCodeError

Constant Summary collapse

CONTENT =

this structure declares what we support in the request Accept: header and defines automatic processing of the response based on the response Content-type: header

{
  json: {
    type: 'application/json',
    proc: proc { |text| JSON.parse(text, symobolize_names: true) },
  },
  html: {
    type: 'text/html',
    proc: proc { |text| text },
  },
  text: {
    type: 'text/plain',
    proc: proc { |text| text },
  },
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host = 'localhost', options = {}) {|_self| ... } ⇒ Mudbug

Returns a new instance of Mudbug.

Yields:

  • (_self)

Yield Parameters:

  • _self (Mudbug)

    the object that the method was called on



88
89
90
91
92
93
94
95
# File 'lib/mudbug.rb', line 88

def initialize(host = 'localhost', options = {})
  @host = host
  https = options.delete(:https)
  @protocol = https ? 'https' : 'http'
  @options = options
  accept :json, :html, :text
  yield self if block_given?
end

Instance Attribute Details

#hostObject

Returns the value of attribute host.



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

def host
  @host
end

#optionsObject (readonly)

Returns the value of attribute options.



85
86
87
# File 'lib/mudbug.rb', line 85

def options
  @options
end

#protocolObject

Returns the value of attribute protocol.



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

def protocol
  @protocol
end

Class Method Details

.accept_header(*types) ⇒ Object

map our internal symbols to HTTP content types assign q scores based on the parameter order construct the right side of the Accept: header



40
41
42
43
44
45
46
# File 'lib/mudbug.rb', line 40

def self.accept_header(*types)
  types.map.with_index { |t, i|
    type = CONTENT[t] ? CONTENT[t][:type] : "application/#{t.to_s.downcase}"
    quality = "q=" << sprintf("%0.1f", 1.0 - i*0.1)
    i == 0 ? type : [type, quality].join(';')
  }.join(', ')
end

.process(resp, accept = nil) ⇒ Object

do stuff based on response’s Content-type accept is e.g. [:json, :html]



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
# File 'lib/mudbug.rb', line 51

def self.process(resp, accept = nil)
  @lager.debug { "accept: #{accept}" }
  @lager.debug { "response code: #{resp.code}" }
  @lager.debug { "response headers:\n" << resp.raw_headers.inspect }

  unless (200..299).include?(resp.code)
    @lager.warn { "processing with HTTP Status Code #{resp.code}" }
  end

  # do you even Content-type, bro?
  ct = resp.headers[:content_type]
  unless ct
    @lager.warn { "abandon processing -- no response Content-type" }
    return resp.body
  end

  # get the content-type
  ct, charset = ct.split(';').map { |s| s.strip }
  @lager.info { "got charset: #{charset}; ignoring" } if charset

  # raise if we got Content-type we didn't ask for
  if accept and !accept.include?(ct)
    raise ContentTypeError, "Asked for #{accept} but got #{ct}"
  end

  # process the response for known content types
  CONTENT.each { |sym, hsh|
    return hsh[:proc].call(resp.body) if ct == hsh[:type]
  }

  @lager.warn { "abandon processing -- unrecognized Content-type: #{ct}" }
  return resp.body
end

.versionObject



6
7
8
9
# File 'lib/mudbug.rb', line 6

def self.version
  file = File.expand_path('../../VERSION', __FILE__)
  File.read(file).chomp
end

Instance Method Details

#accept(*types) ⇒ Object

Writes the Accept: header for you e.g. accept :json, :html # Accept: application/json, text/html accept nil # remove Accept: header Now adds q-scores automatically based on order Note: the hard work is done by the class method



104
105
106
107
108
109
# File 'lib/mudbug.rb', line 104

def accept(*types)
  types = types.first if types.first.is_a?(Array)
  @options[:headers] ||= {}
  return @options[:headers].delete(:accept) if types.first.nil?
  @options[:headers][:accept] = self.class.accept_header(*types)
end

#resource(path) ⇒ Object

use this method directly if you want finer-grained request and response handling supports /path/to/res, path/to/res, host.com/path/to/res



115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/mudbug.rb', line 115

def resource(path)
  uri = URI.parse(path)
  if uri.host # a full URL was passed in
    @host = uri.host
    @protocol = uri.scheme
    url = uri.to_s
  else
    path = "/#{path}" unless path[0,1] == '/'
    url = "#{@protocol}://#{@host}#{path}"
  end
  RestClient::Resource.new(url, @options)
end