Class: Request

Inherits:
Object show all
Includes:
Chainable, CodeEvents
Defined in:
lib/source/redshift/request.rb

Defined Under Namespace

Classes: HTML, HeaderError, HttpMethodError, JSON, Response

Constant Summary collapse

METHODS =
%w(GET POST PUT DELETE)
OPTIONS =
{
  :url           => '',
  :data          => {},
  :link          => 'ignore',
  :async         => true,
  :format        => nil,
  :method        => 'post',
  :encoding      => 'utf-8',
  :is_success    => nil,
  :emulation     => true,
  :url_encoded   => true,
  :eval_scripts  => false,
  :eval_response => false,
  :headers       => {
    'X-Requested-With' => 'XMLHttpRequest',
    'Accept'           => 'text/javascript, text/html, application/xml, text/xml, */*'
  }
}

Instance Method Summary collapse

Methods included from Chainable

#call_chain, #chain, #clear_chain

Methods included from CodeEvents

#fire, #ignore, #upon

Constructor Details

#initialize(options = {}) ⇒ Request

call-seq:

Request.new(options = {}) -> request

Returns a new request with the given options.



42
43
44
45
46
47
48
49
# File 'lib/source/redshift/request.rb', line 42

def initialize(options = {})
  `this.__xhr__ = typeof(ActiveXObject)=='undefined' ? new XMLHttpRequest : new ActiveXObject('MSXML2.XMLHTTP')`
  @options = OPTIONS.merge(options)
  `#{@options[:headers]}.__xhr__=this.__xhr__`  # MooTools sets the ResponseHeaders in the xhr
  # def (@options[:headers]).[](name)             # only during execution, but allows you to get
  #   `this.__xhr__.getResponseHeader(name)`      # at them at any time. I'm not sure whether it
  # end                                           # is necessary for us to emulate this exactly.
end

Instance Method Details

#cancelObject

call-seq:

req.cancel -> req

Cancels the request, fires its “cancel” callback, and returns req.



56
57
58
59
60
61
62
63
64
# File 'lib/source/redshift/request.rb', line 56

def cancel
  return self unless @running
  @running = false
  `this.__xhr__.abort`
  `this.__xhr__.onreadystatechange=function(){;}`
  `this.__xhr__=typeof(ActiveXObject)=='undefined' ? new XMLHttpRequest : new ActiveXObject('MSXML2.XMLHTTP')`
  self.fire(:cancel)
  return self
end

#check(*args, &block) ⇒ Object

call-seq:

req.check(arg, ...) { |request,args_array| block } -> true or false

returns true when Request object is not running or gets cancelled, otherwise returns false. also, seems equipped to ‘chain’ some additional function after itself



72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/source/redshift/request.rb', line 72

def check(*args, &block)
  return true unless @running
  case @options[:link]
  when 'cancel'
    self.cancel
    return true
  when 'chain'
    # self.chain(&block(self,args))
    return false
  end
  return false
end

#execute(options = {}) ⇒ Object

call-seq:

req.execute(options = {}) -> req

Returns req immediately if the request is already running. Otherwise, opens a connection and sends the data provided with the specified options.

Raises:



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/source/redshift/request.rb', line 91

def execute(options = {})
  # return self unless self.check(options)
  @options.update(options)
  raise(TypeError, 'can\'t convert %s to a String' % @options[:url].inspect) unless [String].include?(@options[:url].class)
  raise(TypeError, 'can\'t convert %s to a String' % @options[:method].inspect) unless [String, Symbol].include?(@options[:method].class)
  raise(TypeError, 'can\'t convert %s to a Hash' % @options[:data].inspect) unless [Hash].include?(@options[:data].class)
  raise(HttpMethodError, 'invalid HTTP method "%s" for %s' % [@options[:method],self]) unless METHODS.include?(method = @options[:method].to_s.upcase)
  
  @running = true
  data = @options[:data].to_query_string
  url = @options[:url]
  
  if @options[:format]
    format = "format=%s" % @options[:format]
    data   = data.empty? ? format : [format, data].join('&')
  end
  
  if @options[:emulation] && %w(PUT DELETE).include?(method)
    _method = "_method=%s" % method
    data    = data.empty? ? _method : [_method, data].join('&')
    method  = 'POST'
  end
  
  if @options[:url_encoded] && method == 'POST'
    encoding = @options[:encoding] ? "; charset=%s" % @options[:encoding] : ""
    self.headers['Content-type'] = "application/x-www-form-urlencoded" + encoding
  end
  
  if data && method == 'GET'
    separator = url.include?('?') ? "&" : "?"
    url       = [url, data].join(separator)
    data      = nil
  end
  
  `this.__xhr__.open(method.__value__, url.__value__, #{@options[:async]})`
  `this.__xhr__.onreadystatechange = #{self.on_state_change}.__block__`
  
  @options[:headers].each do |k,v|
    `this.__xhr__.setRequestHeader(k.__value__,v.__value__)`
  # raise(HeaderError, "#{k} => #{v}")
  end
  
  self.fire(:request)
  `this.__xhr__.send($T(data)?data.__value__:'')`
  self.on_state_change.call unless @options[:async]
  return self
end

#headersObject

call-seq:

req.headers -> hash

Returns req’s HTTP headers as a Hash.



144
145
146
# File 'lib/source/redshift/request.rb', line 144

def headers
  @options[:headers]
end

#on_state_changeObject

call-seq:

req.on_state_change -> proc

Returns a Proc object



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/source/redshift/request.rb', line 153

def on_state_change
  Proc.new do
    `var xhr=this.__xhr__`
    `if(xhr.readyState!=4||!#{@running}){return nil;}`
    
    @running = false
    @status  = 0
    
    `try{#{@status}=xhr.status}catch(e){;}`
    
    if self.success?
      @response = Response.new(self.process_scripts(`$q(xhr.responseText)`), `xhr.responseXML`)
      self.fire(:response, 0, @response).fire(:success, 0, @response).call_chain
    else
      @response = Response.new(nil,nil)
      self.fire(:response, 0, @response).fire(:failure, 0, @xhr)
    end
    
    `xhr.onreadystatechange=function(){;}`
    
    return nil
  end
end

#process_scripts(str) ⇒ Object

call-seq:

req.process_scripts(str) -> string or object

If the HTTP response consists of JavaScript alone or if req’s eval_response option is set to true, evaluates the entire text of the response as JavaScript and returns the result.

Otherwise, returns a copy of str with any <script> tags and their content removed. If req’s eval_scripts option is set to true, evaluates the removed scripts.



188
189
190
191
# File 'lib/source/redshift/request.rb', line 188

def process_scripts(str)
  return Document.execute_js(str) if @options[:eval_response] || `/(ecma|java)script/.test(this.__xhr__.getResponseHeader('Content-Type'))`
  return str.strip_scripts(@options[:eval_scripts])
end

#success?Boolean

call-seq:

req.success? -> true or false

Returns true if req’s status is in the 200s, false otherwise.

Returns:

  • (Boolean)


198
199
200
# File 'lib/source/redshift/request.rb', line 198

def success?
  `#{@status}>=200&&#{@status}<300`
end