Class: H8::Value

Inherits:
Object show all
Includes:
Comparable
Defined in:
lib/h8/value.rb,
ext/h8/main.cpp

Overview

Wrapper for javascript objects.

Important: when accessing fields of the object, respond_to? will not work due to js notation, instead, check the returned value (there will be always one) to not to be value.undefined?

Precaution! Values are always bounded to the context where they are created. You can not pass values between context, as they often map native Javascript objects. If you need, you can copy, for example, by converting it H8::Value#to_ruby first. Another approach is to use JSON serialization from the script.

Interesting thing about H8::Value is that when passed back to some javascript environment (say, callback parameted or as a global variable), it unwraps source javascript object - no copying, no modifying.

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_sym, *arguments, &block) ⇒ Object

Optimizing JS member access. Support class members and member functions - will call them automatically. Use val to get callable instead.

First invocation creates accessor method so future calls happen much faster



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/h8/value.rb', line 45

def method_missing(method_sym, *arguments, &block)
  name = method_sym.to_s
  if name[-1] != '='
    instance_eval <<-End
            def #{name} *args, **kwargs
              res = _get_attr('#{name}')
              (res.is_a?(H8::Value) && res.function?) ? res.apply(self,*args) : res
            end
    End
  else
    instance_eval <<-End
            def #{name} value
              _set_attr('#{name[0..-2]}', value)
            end
    End
  end
  send method_sym, *arguments
end

Instance Method Details

#<=>(other) ⇒ Object

Compare to other object, either usual or another Value instance. Tries its best. be sure to use it wisely and report any problems



66
67
68
69
# File 'lib/h8/value.rb', line 66

def <=> other
  other = other.to_ruby if other.is_a?(H8::Value)
  to_ruby <=> other
end

#[](name_index) ⇒ H8::Value

Get js object attribute by either name or index (should be Fixnum instance). It always return H8::Value instance, check it to (not) be undefined? to see if there is such attribute

Returns:

  • (H8::Value)

    instance, which is .undefined? if does not exist



31
32
33
# File 'lib/h8/value.rb', line 31

def [] name_index
  name_index.is_a?(Fixnum) ? _get_index(name_index) : _get_attr(name_index.to_s)
end

#[]=(name_index, value) ⇒ Object

Set js object attribute by either name or index (should be Fixnum instance).



36
37
38
39
# File 'lib/h8/value.rb', line 36

def []= name_index, value
  # name_index.is_a?(Fixnum) ? _get_index(name_index) : _get_attr(name_index.to_s)
  _set_attr(name_index.to_s, value)
end

#apply(this, *args) ⇒ H8::Value

Like JS apply: call the value that should be function() bounded to a given object

Parameters:

  • this (Object)

    object to bound call to

  • args

    any arguments

Returns:

  • (H8::Value)

    result returned by the function which might be undefined



82
83
84
# File 'lib/h8/value.rb', line 82

def apply this, *args
  _apply this, args
end

#array?Boolean

native method. stub for documentation

Returns:

  • (Boolean)


167
168
# File 'lib/h8/value.rb', line 167

def array? # native method. stub for documentation
end

#call(*args) ⇒ H8::Value

Call javascript function represented by this instance (which should be function()) with given (or no) arguments.

Returns:

  • (H8::Value)

    function return which might be undefined



74
75
76
# File 'lib/h8/value.rb', line 74

def call *args
  _call args
end

#contextH8::Context

Returns context to which this value is bounded.

Returns:

  • (H8::Context)

    context to which this value is bounded



171
172
# File 'lib/h8/value.rb', line 171

def context # native method. stub for documentation
end

#eachObject

enumerate |key, value| pairs for javascript object attributes



102
103
104
105
106
107
# File 'lib/h8/value.rb', line 102

def each
  return enum_for(:each) unless block_given? # Sparkling magic!
  keys.each { |k|
    yield k, _get_attr(k)
  }
end

#each_keyObject

Iterate over javascript object keys



119
120
121
# File 'lib/h8/value.rb', line 119

def each_key
  keys.each
end

#each_valueObject

iterate over values of the javascript object attributes



129
130
131
# File 'lib/h8/value.rb', line 129

def each_value
  values.each
end

#function?Boolean

native method. stub for documentation

Returns:

  • (Boolean)


158
159
# File 'lib/h8/value.rb', line 158

def function? # native method. stub for documentation
end

#inspectObject



23
24
25
# File 'lib/h8/value.rb', line 23

def inspect
  "<H8::Value #{to_ruby rescue '(too deep)'}>"
end

#keysObject

Generate set of keys of the wrapped object



96
97
98
99
# File 'lib/h8/value.rb', line 96

def keys
  context[:__obj] = self
  Set.new context.eval("(Object.keys(__obj));").to_a
end

#object?Boolean

native method. stub for documentation

Returns:

  • (Boolean)


161
162
# File 'lib/h8/value.rb', line 161

def object? # native method. stub for documentation
end

#to_aryObject Also known as: to_a

Tries to convert JS object to ruby array

Raises:

  • H8::Error if the JS object is not an array



88
89
90
91
# File 'lib/h8/value.rb', line 88

def to_ary
  raise Error, 'Is not an array' unless array?
  to_ruby
end

#to_h(depth = 0) ⇒ Object

Try to convert javascript object to a ruby hash



110
111
112
# File 'lib/h8/value.rb', line 110

def to_h depth=0
  each.reduce({}) { |all, kv| all[kv[0]] = kv[1].to_ruby depth; all }
end

#to_json(*params) ⇒ Object



114
115
116
# File 'lib/h8/value.rb', line 114

def to_json *params
  __rb_to_js
end

#to_procObject

Convert to Proc instance so it could be used as &block parameter



176
177
178
179
# File 'lib/h8/value.rb', line 176

def to_proc
  function? or raise H8::Error, 'JS object is not a function'
  -> (*args) { call *args }
end

#to_ruby(depth = 0) ⇒ Object

Tries to convert wrapped JS object to ruby primitive (Fixed, String, Float, Array, Hash). Note that this conversion looses information about source javascript class (if any).

Raises:

  • H8::Error if the data structure is too deep (e.g. cyclic)



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/h8/value.rb', line 137

def to_ruby depth=0
  depth += 1
  raise H8::Error, "object tree too deep" if depth > 100
  case
    when integer?
      to_i
    when string?
      to_s
    when float?
      to_f
    when array?
      _get_attr('length').to_i.times.map { |i| _get_index(i).to_ruby depth }
    when function?
      to_proc
    when object?
      to_h depth
    else
      raise Error, "Dont know how to convert #{self.class}"
  end
end

#to_strObject



181
182
183
# File 'lib/h8/value.rb', line 181

def to_str
  to_s
end

#undefined?Boolean

native method. stub for documentation

Returns:

  • (Boolean)


164
165
# File 'lib/h8/value.rb', line 164

def undefined? # native method. stub for documentation
end

#valuesArray

Returns values array. does NOT convert values to_ruby().

Returns:

  • (Array)

    values array. does NOT convert values to_ruby()



124
125
126
# File 'lib/h8/value.rb', line 124

def values
  each.reduce([]) { |all, kv| all << kv[1]; all }
end