Class: JsshObject

Inherits:
Object
  • Object
show all
Defined in:
lib/vapir-firefox/jssh_socket.rb

Overview

represents a javascript object in ruby.

Direct Known Subclasses

JsshArray, JsshDOMNode, JsshHash

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ref, jssh_socket, other = {}) ⇒ JsshObject

initializes a JsshObject with a string of javascript containing a reference to the object, and a JsshSocket that the object is defined on.

Raises:

  • (ArgumentError)


764
765
766
767
768
769
770
771
772
773
774
# File 'lib/vapir-firefox/jssh_socket.rb', line 764

def initialize(ref, jssh_socket, other={})
  other={:debug_name => ref, :function_result => false}.merge(other)
  raise ArgumentError, "Empty object reference!" if !ref || ref==''
  raise ArgumentError, "Reference must be a string - got #{ref.inspect} (#{ref.class.name})" unless ref.is_a?(String)
  raise ArgumentError, "Not given a JsshSocket, instead given #{jssh_socket.inspect} (#{jssh_socket.class.name})" unless jssh_socket.is_a?(JsshSocket)
  @ref=ref
  @jssh_socket=jssh_socket
  @debug_name=other[:debug_name]
  @function_result=other[:function_result]
#    logger.info { "#{self.class} initialized: #{debug_name} (type #{type})" }
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object

method_missing handles unknown method calls in a way that makes it possible to write javascript-like syntax in ruby, to some extent.

method_missing checks the attribute of the represented javascript object with with the name of the given method. if that attribute refers to a function, then that function is called with any given arguments (like #invoke does). If that attribute is undefined, an error will be raised, unless a ‘?’ suffix is used (see below).

method_missing will only try to deal with methods that look like /^[a-z_]*$/i - no special characters, only alphanumeric/underscores, starting with alpha or underscore - with the exception of three special behaviors:

If the method ends with an equals sign (=), it does assignment - it calls #assign on the given attribute, with the given (single) argument, to do the assignment and returns the assigned value.

If the method ends with a bang (!), then it will attempt to get the value of the reference, using JsshObject#val, which converts the javascript to json and then to ruby. For simple types (null, string, boolean, number), this is what gets returned anyway. With other types (usually the ‘object’ type), attempting to convert to json can raise errors or cause infinite recursion, so is not attempted. but if you have an object or an array that you know you can json-ize, you can use ! to force that.

If the method ends with a question mark (?), then if the attribute is undefined, no error is raised (as usually happens) - instead nil is just returned.

otherwise, method_missing behaves like #invoke, and returns a JsshObject, a string, a boolean, a number, or null.

Since method_missing returns a JsshObject for javascript objects, this means that you can string together method_missings and the result looks rather like javascript. – $A and $H, used below, are methods of the Prototype javascript library, which add nice functional methods to arrays and hashes - see www.prototypejs.org/ You can use these methods with method_missing just like any other:

>> js_hash=jssh_socket.object('$H')
=> #<JsshObject:0x2beb598 @ref="$H" ...>
>> js_arr=jssh_socket.object('$A')
=> #<JsshObject:0x2be40e0 @ref="$A" ...>

>> js_arr.call(document.body.childNodes).pluck! :tagName
=> ["TEXTAREA", "DIV", "NOSCRIPT", "DIV", "DIV", "DIV", "BR", "TABLE", "DIV", "DIV", "DIV", "TEXTAREA", "DIV", "DIV", "SCRIPT"]
>> js_arr.call(document.body.childNodes).pluck! :id
=> ["csi", "header", "", "ssb", "tbd", "res", "", "nav", "wml", "", "", "hcache", "xjsd", "xjsi", ""]
>> js_hash.call(document.getElementById('tbd')).keys!
=> ["addEventListener", "appendChild", "className", "parentNode", "getElementsByTagName", "title", ...]


1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
# File 'lib/vapir-firefox/jssh_socket.rb', line 1169

def method_missing(method, *args)
  method=method.to_s
  if method =~ /\A([a-z_][a-z0-9_]*)([=?!])?\z/i
    method = $1
    suffix = $2
    attr(method).assign_or_call_or_val_or_object_by_suffix(suffix, *args)
  else
    # don't deal with any special character crap 
    super
  end
end

Instance Attribute Details

#debug_nameObject (readonly)

this tracks the origins of this object - what calls were made along the way to get it.



753
754
755
# File 'lib/vapir-firefox/jssh_socket.rb', line 753

def debug_name
  @debug_name
end

#function_resultObject (readonly)

whether this represents the result of a function call (if it does, then JsshSocket#typeof won’t be called on it)



751
752
753
# File 'lib/vapir-firefox/jssh_socket.rb', line 751

def function_result
  @function_result
end

#jssh_socketObject (readonly)

the JsshSocket this JsshObject is on



749
750
751
# File 'lib/vapir-firefox/jssh_socket.rb', line 749

def jssh_socket
  @jssh_socket
end

#refObject (readonly)

the reference to the javascript object this JsshObject represents



747
748
749
# File 'lib/vapir-firefox/jssh_socket.rb', line 747

def ref
  @ref
end

Class Method Details

.always_define_methodsObject

whether JsshObject shall try to dynamically define methods on initialization, using #define_methods! default is false.



783
784
785
786
787
788
789
# File 'lib/vapir-firefox/jssh_socket.rb', line 783

def self.always_define_methods
  unless class_variable_defined?('@@always_define_methods')
    # if not defined, set the default. 
    @@always_define_methods=false
  end
  @@always_define_methods
end

.always_define_methods=(val) ⇒ Object

set whether JsshObject shall try to dynamically define methods in #val_or_object, using #define_methods!

I find this useful to set to true in irb, for tab-completion of methods. it may cause jssh operations to be considerably slower, however.

for always setting this in irb, I set this beforehand, overriding the default, by including in my .irbrc the following (which doesn’t require jssh_socket.rb to be required):

class JsshObject
  @@always_define_methods=true
end


803
804
805
# File 'lib/vapir-firefox/jssh_socket.rb', line 803

def self.always_define_methods=(val)
  @@always_define_methods = val
end

Instance Method Details

#%(operand) ⇒ Object

modulus, using the % operator in javascript



1093
1094
1095
# File 'lib/vapir-firefox/jssh_socket.rb', line 1093

def %(operand)
  binary_operator('%', operand)
end

#*(operand) ⇒ Object

multiplication, using the * operator in javascript



1089
1090
1091
# File 'lib/vapir-firefox/jssh_socket.rb', line 1089

def *(operand)
  binary_operator('*', operand)
end

#+(operand) ⇒ Object

addition, using the + operator in javascript



1077
1078
1079
# File 'lib/vapir-firefox/jssh_socket.rb', line 1077

def +(operand)
  binary_operator('+', operand)
end

#-(operand) ⇒ Object

subtraction, using the - operator in javascript



1081
1082
1083
# File 'lib/vapir-firefox/jssh_socket.rb', line 1081

def -(operand)
  binary_operator('-', operand)
end

#/(operand) ⇒ Object

division, using the / operator in javascript



1085
1086
1087
# File 'lib/vapir-firefox/jssh_socket.rb', line 1085

def /(operand)
  binary_operator('/', operand)
end

#<(operand) ⇒ Object

inequality, using the < operator in javascript



1110
1111
1112
# File 'lib/vapir-firefox/jssh_socket.rb', line 1110

def <(operand)
  binary_operator('<', operand)
end

#<=(operand) ⇒ Object

inequality, using the <= operator in javascript



1118
1119
1120
# File 'lib/vapir-firefox/jssh_socket.rb', line 1118

def <=(operand)
  binary_operator('<=', operand)
end

#==(operand) ⇒ Object

returns true if the javascript object represented by this is equal to the given operand.



1097
1098
1099
# File 'lib/vapir-firefox/jssh_socket.rb', line 1097

def ==(operand)
  operand.is_a?(JsshObject) && binary_operator('==', operand)
end

#>(operand) ⇒ Object

inequality, using the > operator in javascript



1106
1107
1108
# File 'lib/vapir-firefox/jssh_socket.rb', line 1106

def >(operand)
  binary_operator('>', operand)
end

#>=(operand) ⇒ Object

inequality, using the >= operator in javascript



1114
1115
1116
# File 'lib/vapir-firefox/jssh_socket.rb', line 1114

def >=(operand)
  binary_operator('>=', operand)
end

#[](key) ⇒ Object

returns a JsshObject referring to a subscript of this object, or a value if it is simple (see #val_or_object)

subscript is specified as ruby (converted to javascript).



1060
1061
1062
# File 'lib/vapir-firefox/jssh_socket.rb', line 1060

def [](key)
  sub(key).val_or_object(:error_on_undefined => false)
end

#[]=(key, value) ⇒ Object

assigns the given ruby value (which is converted to javascript) to the given subscript (the key is also converted to javascript).



1066
1067
1068
# File 'lib/vapir-firefox/jssh_socket.rb', line 1066

def []=(key, value)
  self.sub(key).assign(value)
end

#assign(val) ⇒ Object

assigns the given ruby value (converted to javascript) to the reference for this object. returns self.



959
960
961
962
963
964
# File 'lib/vapir-firefox/jssh_socket.rb', line 959

def assign(val)
  @debug_name="(#{debug_name}=#{val.is_a?(JsshObject) ? val.debug_name : JsshSocket.to_javascript(val)})"
  result=assign_expr(JsshSocket.to_javascript(val))
#    logger.info { "#{self.class} assigned: #{debug_name} (type #{type})" }
  result
end

#assign_expr(val) ⇒ Object

assigns the given javascript expression (string) to the reference for this object



966
967
968
969
970
971
972
973
974
# File 'lib/vapir-firefox/jssh_socket.rb', line 966

def assign_expr(val)
  jssh_socket.value_json("(function(val){#{ref}=val; return null;}(#{val}))")
  @type=nil # uncache this 
  # don't want to use JsshSocket#assign_json because converting the result of the assignment (that is, the expression assigned) to json is error-prone and we don't really care about the result. 
  # don't want to use JsshSocket#assign because the result can be blank and cause send_and_read to wait for data that's not coming - also 
  # using a json function is better because it catches errors much more elegantly. 
  # so, wrap it in a function that returns nil. 
  self
end

#assign_or_call_or_val_or_object_by_suffix(suffix, *args) ⇒ Object

does the work of #method_missing to determine whether to call a function what to return based on the defined behavior of the given suffix. see #method_missing for more. information.



910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
# File 'lib/vapir-firefox/jssh_socket.rb', line 910

def assign_or_call_or_val_or_object_by_suffix(suffix, *args)
  if suffix=='='
    assign(*args)
  else
    obj = if type=='function'
      pass(*args)
    elsif !args.empty?
      raise ArgumentError, "Cannot pass arguments to Javascript object #{inspect} (ref = #{ref})"
    else
      self
    end
    case suffix
    when nil
      obj.val_or_object
    when '?'
      obj.val_or_object(:error_on_undefined => false)
    when '!'
      obj.val
    else
      raise ArgumentError, "suffix should be one of: nil, '?', '!', '='; got: #{suffix.inspect}"
    end
  end
end

#attr(attribute, options = {}) ⇒ Object

returns a JsshObject referencing the given attribute of this object



950
951
952
953
954
955
# File 'lib/vapir-firefox/jssh_socket.rb', line 950

def attr(attribute, options={})
  unless (attribute.is_a?(String) || attribute.is_a?(Symbol)) && attribute.to_s =~ /\A[a-z_][a-z0-9_]*\z/i
    raise JsshSyntaxError, "#{attribute.inspect} (#{attribute.class.inspect}) is not a valid attribute!"
  end
  JsshObject.new("#{ref}.#{attribute}", jssh_socket, :debug_name => "#{debug_name}.#{attribute}")
end

#binary_operator(operator, operand) ⇒ Object

calls a binary operator (in javascript) with self and another operand.

the operator should be string of javascript; the operand will be converted to javascript.



1073
1074
1075
# File 'lib/vapir-firefox/jssh_socket.rb', line 1073

def binary_operator(operator, operand)
  JsshObject.new("(#{ref}#{operator}#{JsshSocket.to_javascript(operand)})", jssh_socket, :debug_name => "(#{debug_name}#{operator}#{operand.is_a?(JsshObject) ? operand.debug_name : JsshSocket.to_javascript(operand)})").val_or_object
end

#call(*args) ⇒ Object

returns the value (via JsshSocket#value_json) or a JsshObject (see #val_or_object) of the return value of this function (assumes this object is a function) passing it the given arguments (which are converted to javascript).

simply, it just calls self.pass(*args).val_or_object



987
988
989
# File 'lib/vapir-firefox/jssh_socket.rb', line 987

def call(*args)
  pass(*args).val_or_object
end

#define_methods!Object

calls define_method for each key of this object as a hash. useful for tab-completing attributes in irb, mostly.



1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
# File 'lib/vapir-firefox/jssh_socket.rb', line 1182

def define_methods! # :nodoc:
  metaclass=(class << self; self; end)
  keys=jssh_socket.object("function(obj) { var keys=[]; for(var key in obj) { keys.push(key); } return keys; }").pass(self).val
  
  keys.grep(/\A[a-z_][a-z0-9_]*\z/i).reject{|k| self.class.method_defined?(k)}.each do |key|
    metaclass.send(:define_method, key) do |*args|
      invoke(key, *args)
    end
  end
end

#implemented_interfacesObject

returns an array of interfaces which this object is an instance of. this is achieved by looping over each value of Components.interfaces (see developer.mozilla.org/en/Components.interfaces ) and calling the #instanceof operator with this and the interface.

this may be rather slow.



843
844
845
846
847
848
# File 'lib/vapir-firefox/jssh_socket.rb', line 843

def implemented_interfaces
  jssh_socket.Components.interfaces.to_hash.inject([]) do |list, (key, interface)|
    list << interface if instanceof(interface)
    list
  end
end

#inspectObject

represents this javascript object in one line, displaying the type and debug name.



1301
1302
1303
# File 'lib/vapir-firefox/jssh_socket.rb', line 1301

def inspect
  "\#<#{self.class.name}:0x#{"%.8x"%(self.hash*2)} #{[:type, :debug_name].map{|attr| attr.to_s+'='+send(attr).to_s}.join(', ')}>"
end

#instanceof(interface) ⇒ Object

calls the javascript instanceof operator on this object and the given interface (expected to be a JsshObject) note that the javascript instanceof operator is not to be confused with ruby’s #instance_of? method - this takes a javascript interface; #instance_of? takes a ruby module.

example:

window.instanceof(window.jssh_socket.Components.interfaces.nsIDOMChromeWindow)
=> true


835
836
837
# File 'lib/vapir-firefox/jssh_socket.rb', line 835

def instanceof(interface)
  jssh_socket.instanceof(self.ref, interface.ref)
end

#invoke(attribute, *args) ⇒ Object

returns a JsshObject representing the given attribute. Checks the type, and if it is a function, calls the function with any arguments given (which are converted to javascript) and returns the return value of the function (or nil if the function returns undefined).

If the attribute is undefined, raises an error (if you want an attribute even if it’s undefined, use #invoke? or #attr).



940
941
942
# File 'lib/vapir-firefox/jssh_socket.rb', line 940

def invoke(attribute, *args)
  attr(attribute).assign_or_call_or_val_or_object_by_suffix(nil, *args)
end

#invoke?(attribute, *args) ⇒ Boolean

same as #invoke, but returns nil for undefined attributes rather than raising an error.

Returns:

  • (Boolean)


945
946
947
# File 'lib/vapir-firefox/jssh_socket.rb', line 945

def invoke?(attribute, *args)
  attr(attribute).assign_or_call_or_val_or_object_by_suffix('?', *args)
end

#new(*args) ⇒ Object

assuming the javascript object represented is a constructor, this returns a new instance passing the given arguments.

date_class = jssh_socket.object('Date')
=> #<JsshObject:0x0118eee8 type=function, debug_name=Date>
date = date_class.new
=> #<JsshObject:0x01188a84 type=object, debug_name=new Date()>
date.getFullYear
=> 2010
date_class.new('october 4, 1978').getFullYear
=> 1978


1002
1003
1004
# File 'lib/vapir-firefox/jssh_socket.rb', line 1002

def new(*args)
  JsshObject.new("new #{ref}", jssh_socket, :debug_name => "new #{debug_name}").call(*args)
end

#object_respond_to?(method) ⇒ Boolean

returns true if the javascript object this represents responds to the given method. this does not pay attention to any defined ruby methods, just javascript.

Returns:

  • (Boolean)


1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
# File 'lib/vapir-firefox/jssh_socket.rb', line 1199

def object_respond_to?(method)
  method=method.to_s
  if method =~ /^([a-z_][a-z0-9_]*)([=?!])?$/i
    method = $1
    suffix = $2
  else # don't deal with any special character crap 
    return false
  end

  if self.type=='undefined'
    return false
  elsif suffix=='='
    if self.type=='object'
      return true # yeah, you can generally assign attributes to objects
    else
      return false # no, you can't generally assign attributes to (boolean, number, string, null)
    end
  else
    attr=attr(method)
    return attr.type!='undefined'
  end
end

#object_typeObject

returns the type of object that is reported by the javascript toString() method, which returns such as “[object Object]” or “[object XPCNativeWrapper [object HTMLDocument]]” This method returns ‘Object’ or ‘XPCNativeWrapper [object HTMLDocument]’ respectively. Raises an error if this JsshObject points to something other than a javascript ‘object’ type (‘function’ or ‘number’ or whatever)

this isn’t used, doesn’t seem useful, and may go away in the future.



857
858
859
860
861
862
863
864
865
866
867
# File 'lib/vapir-firefox/jssh_socket.rb', line 857

def object_type
  @object_type ||= begin
    case type
    when 'object'
      self.toString! =~ /\A\[object\s+(.*)\]\Z/
      $1
    else
      raise JsshError, "Type is #{type}, not object"
    end
  end
end

#pass(*args) ⇒ Object

returns a JsshObject for the result of calling the function represented by this object, passing the given arguments, which are converted to javascript. if this is not a function, javascript will raise an error.



978
979
980
# File 'lib/vapir-firefox/jssh_socket.rb', line 978

def pass(*args)
  JsshObject.new("#{ref}(#{args.map{|arg| JsshSocket.to_javascript(arg)}.join(', ')})", jssh_socket, :function_result => true, :debug_name => "#{debug_name}(#{args.map{|arg| arg.is_a?(JsshObject) ? arg.debug_name : JsshSocket.to_javascript(arg)}.join(', ')})")
end

#pretty_print(pp) ⇒ Object

:nodoc:



1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
# File 'lib/vapir-firefox/jssh_socket.rb', line 1304

def pretty_print(pp) # :nodoc:
  pp.object_address_group(self) do
    pp.seplist([:type, :debug_name], lambda { pp.text ',' }) do |attr|
      pp.breakable ' '
      pp.group(0) do
        pp.text attr.to_s
        pp.text ': '
        #pp.breakable
        pp.text send(attr)
      end
    end
  end
end

#respond_to?(method, include_private = false) ⇒ Boolean

returns true if this object responds to the given method (that is, it’s a defined ruby method) or if #method_missing will handle it

Returns:

  • (Boolean)


1194
1195
1196
# File 'lib/vapir-firefox/jssh_socket.rb', line 1194

def respond_to?(method, include_private = false)
  super || object_respond_to?(method)
end

#store(js_variable, somewhere_meaningful = true) ⇒ Object

sets the given javascript variable to this object, and returns a JsshObject referring to the variable.

>> foo=document.getElementById('guser').store('foo')
=> #<JsshObject:0x2dff870 @ref="foo" ...>
>> foo.tagName
=> "DIV"

the second argument is only used internally and shouldn’t be used.



1015
1016
1017
1018
1019
# File 'lib/vapir-firefox/jssh_socket.rb', line 1015

def store(js_variable, somewhere_meaningful=true)
  stored=JsshObject.new(js_variable, jssh_socket, :function_result => false, :debug_name => somewhere_meaningful ? "(#{js_variable}=#{debug_name})" : debug_name)
  stored.assign_expr(self.ref)
  stored
end

#store_rand_object_key(object) ⇒ Object

stores this object in a random key of the given object and returns the stored object.



1037
1038
1039
1040
1041
1042
# File 'lib/vapir-firefox/jssh_socket.rb', line 1037

def store_rand_object_key(object)
  raise ArgumentError("Object is not a JsshObject: got #{object.inspect}") unless object.is_a?(JsshObject)
  store_rand_named do |r|
    object.sub(r).ref
  end
end

#store_rand_tempObject

stores this object in a random key of the designated temporary object for this socket and returns the stored object.



1045
1046
1047
# File 'lib/vapir-firefox/jssh_socket.rb', line 1045

def store_rand_temp
  store_rand_object_key(jssh_socket.temp_object)
end

#sub(key) ⇒ Object

returns a JsshObject referring to a subscript of this object, specified as a ruby object converted to javascript.

similar to [], but [] calls #val_or_object; this always returns a JsshObject.



1053
1054
1055
# File 'lib/vapir-firefox/jssh_socket.rb', line 1053

def sub(key)
  JsshObject.new("#{ref}[#{JsshSocket.to_javascript(key)}]", jssh_socket, :debug_name => "#{debug_name}[#{key.is_a?(JsshObject) ? key.debug_name : JsshSocket.to_javascript(key)}]")
end

#to_arrayObject

returns a JsshArray representing this object



1242
1243
1244
# File 'lib/vapir-firefox/jssh_socket.rb', line 1242

def to_array
  JsshArray.new(self.ref, self.jssh_socket, :debug_name => debug_name)
end

#to_domObject

returns a JsshDOMNode representing this object



1250
1251
1252
# File 'lib/vapir-firefox/jssh_socket.rb', line 1250

def to_dom
  JsshDOMNode.new(self.ref, self.jssh_socket, :debug_name => debug_name)
end

#to_hashObject

returns a JsshHash representing this object



1246
1247
1248
# File 'lib/vapir-firefox/jssh_socket.rb', line 1246

def to_hash
  JsshHash.new(self.ref, self.jssh_socket, :debug_name => debug_name)
end

#to_js_arrayObject

returns this object passed through the $A function of the prototype javascript library.



1230
1231
1232
# File 'lib/vapir-firefox/jssh_socket.rb', line 1230

def to_js_array
  jssh_socket.object('$A').call(self)
end

#to_js_hashObject

returns this object passed through the $H function of the prototype javascript library.



1234
1235
1236
# File 'lib/vapir-firefox/jssh_socket.rb', line 1234

def to_js_hash
  jssh_socket.object('$H').call(self)
end

#to_js_hash_safeObject

returns this object passed through a javascript function which copies each key onto a blank object and rescues any errors.



1238
1239
1240
# File 'lib/vapir-firefox/jssh_socket.rb', line 1238

def to_js_hash_safe
  jssh_socket.object('$_H').call(self)
end

#to_ruby_arrayObject

returns an Array in which each element is the #val_or_Object of each element of this javascript array.



1296
1297
1298
# File 'lib/vapir-firefox/jssh_socket.rb', line 1296

def to_ruby_array
  self.to_array.to_a
end

#to_ruby_hash(options = {}) ⇒ Object

returns a ruby Hash. each key/value pair of this object is represented in the returned hash.

if an error is encountered trying to access the value for an attribute, then in the returned hash, that attribute is set to the error that was encountered rather than the actual value (since the value wasn’t successfully retrieved).

options may be specified. the only option currently supported is:

  • :recurse => a number or nil. if it’s a number, then this will recurse to that depth. If it’s nil, this won’t recurse at all.

below the specified recursion level, this will return this JsshObject rather than recursing down into it.

this function isn’t expected to raise any errors, since encountered errors are set as attribute values.



1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
# File 'lib/vapir-firefox/jssh_socket.rb', line 1270

def to_ruby_hash(options={})
  options={:recurse => 1}.merge(options)
  return self if !options[:recurse] || options[:recurse]==0
  return self if self.type!='object'
  next_options=options.merge(:recurse => options[:recurse]-1)
  begin
    keys=self.to_hash.keys
  rescue JsshError
    return self
  end
  keys.inject({}) do |hash, key|
    val=begin
      self[key]
    rescue JsshError
      $!
    end
    hash[key]=if val.is_a?(JsshObject)
      val.to_ruby_hash(next_options)
    else
      val
    end
    hash
  end
end

#triple_equals(operand) ⇒ Object

javascript triple-equals (===) operator. very different from ruby’s tripl-equals operator - in javascript this means “really really equal”; in ruby it means “sort of equal-ish”



1102
1103
1104
# File 'lib/vapir-firefox/jssh_socket.rb', line 1102

def triple_equals(operand)
  operand.is_a?(JsshObject) && binary_operator('===', operand)
end

#typeObject

returns javascript typeof this object



818
819
820
821
822
823
824
825
# File 'lib/vapir-firefox/jssh_socket.rb', line 818

def type
  if function_result # don't get type for function results, causes function evaluations when you probably didn't want that. 
    nil
  else
#      logger.add(-1) { "retrieving type for #{debug_name}" }
    @type||= jssh_socket.typeof(ref)
  end
end

#valObject

returns the value, via JsshSocket#value_json



777
778
779
# File 'lib/vapir-firefox/jssh_socket.rb', line 777

def val
  jssh_socket.value_json(ref, :error_on_undefined => !function_result)
end

#val_or_object(options = {}) ⇒ Object

checks the type of this object, and if it is a type that can be simply converted to a ruby object via json, returns the ruby value. that occurs if the type is one of:

‘boolean’,‘number’,‘string’,‘null’

otherwise - if the type is something else (probably ‘function’ or ‘object’; or maybe something else) then this JsshObject is returned.

if the object this refers to is undefined in javascript, then behavor depends on the options hash. if :error_on_undefined is true, then nil is returned; otherwise JsshUndefinedValueError is raised.

if this is a function result, this will store the result in a temporary location (thereby calling the function to acquire the result) before making the above decision.

this method also calls #define_methods! on this if JsshObject.always_define_methods is true. this can be overridden in the options hash using the :define_methods key (true or false).



886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
# File 'lib/vapir-firefox/jssh_socket.rb', line 886

def val_or_object(options={})
  options={:error_on_undefined=>true, :define_methods => self.class.always_define_methods}.merge(options)
  if function_result # calling functions multiple times is bad, so store in temp before figuring out what to do with it
    store_rand_object_key(jssh_socket.temp_object).val_or_object(options.merge(:error_on_undefined => false))
  else
    case self.type
    when 'undefined'
      if !options[:error_on_undefined]
        nil
      else
        raise JsshUndefinedValueError, "undefined expression represented by #{self.inspect} (javascript reference is #{@ref})"
      end
    when 'boolean','number','string','null'
      val
    else # 'function','object', or anything else 
      if options[:define_methods] && type=='object'
        define_methods!
      end
      self
    end
  end
end

#val_strObject

returns the value just as a string with no attempt to deal with type using json. via JsshSocket#value

note that this can be slow if it evaluates to a blank string. for example, if ref is just “” then JsshSocket#value will wait DEFAULT_SOCKET_TIMEOUT seconds for data that is not to come. this also happens with functions that return undefined. if ref=“function()do_some_stuff;” (with no return), it will also wait DEFAULT_SOCKET_TIMEOUT.



813
814
815
# File 'lib/vapir-firefox/jssh_socket.rb', line 813

def val_str
  jssh_socket.value(ref)
end