Module: Ryo::Reflect

Extended by:
Reflect
Includes:
Utils
Included in:
Ryo, Reflect
Defined in:
lib/ryo/reflect.rb

Overview

The Ryo::Reflect module mirrors JavaScript’s Relfect object, and some of the static methods on JavaScript’s Object as well.

Ryo::Reflect also implements Ryo-specific reflection features. The instance methods of this module are available as singleton methods on the Ryo module.

JavaScript equivalents (Reflect) collapse

JavaScript equivalents (Object) collapse

Ryo-specific collapse

Instance Method Details

#inspect_object(ryo) ⇒ String

Returns a String representation of a Ryo object

Parameters:

Returns:

  • (String)

    Returns a String representation of a Ryo object



253
254
255
256
257
258
259
260
# File 'lib/ryo/reflect.rb', line 253

def inspect_object(ryo)
  format(
    "#<Ryo object=%{object} proto=%{proto} table=%{table}>",
    object: Object.instance_method(:to_s).bind_call(ryo),
    proto: prototype_of(ryo).inspect,
    table: table_of(ryo).inspect
  )
end

#set_prototype_of(ryo, prototype) ⇒ nil

Equivalent to JavaScript’s Reflect.setPrototypeOf

Parameters:

  • ryo (Ryo)

    A Ryo object.

  • prototype (Ryo)

    The prototype to assign to ryo.

Returns:

  • (nil)


43
44
45
46
47
# File 'lib/ryo/reflect.rb', line 43

def set_prototype_of(ryo, prototype)
  kernel(:instance_variable_set)
    .bind_call(ryo, :@_proto, prototype)
  nil
end

#define_property(ryo, property, value) ⇒ void

This method returns an undefined value.

Equivalent to JavaScript’s Reflect.defineProperty

Parameters:



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/ryo/reflect.rb', line 59

def define_property(ryo, property, value)
  table, property = table_of(ryo), property.to_s
  kernel(:tap).bind_call(value) { _1.bind!(ryo) if function?(_1) }
  table[property] = value
  # Define setter
  if !setter_defined?(ryo, property) && property[-1] != "?"
    define_method!(ryo, "#{property}=") { ryo[property] = _1 }
  end
  # Define getter
  return if getter_defined?(ryo, property)
  define_method!(ryo, property) { |*args, &b|
    (args.empty? && b.nil?) ? ryo[property] :
                            super(*args, &b)
  }
  nil
end

#properties_of(ryo) ⇒ Array<String>

Equivalent to JavaScript’s Reflect.ownKeys, and JavaScript’s Object.keys

Parameters:

Returns:

  • (Array<String>)

    Returns the properties defined on a Ryo object



84
85
86
# File 'lib/ryo/reflect.rb', line 84

def properties_of(ryo)
  table_of(ryo).keys
end

#property?(ryo, property) ⇒ Boolean

Equivalent to JavaScript’s Object.hasOwn, and Object.prototype.hasOwnProperty.

Parameters:

Returns:

  • (Boolean)

    Returns true when the property is a member of a Ryo object



103
104
105
# File 'lib/ryo/reflect.rb', line 103

def property?(ryo, property)
  table_of(ryo).key?(property.to_s)
end

#assign(target, *sources) ⇒ Ryo

Equivalent to JavaScript’s Object.assign.

Parameters:

  • target (Ryo, Hash, #to_hash)

    The target object

  • sources (Ryo, Hash, #to_hash)

    A variable number of source objects that will be merged with the target object

Returns:

  • (Ryo)

    Returns the modified target object.



117
118
119
120
121
122
# File 'lib/ryo/reflect.rb', line 117

def assign(target, *sources)
  sources.each do |source|
    to_hash(source).each { target[_1.to_s] = _2 }
  end
  target
end

#prototype_chain_of(ryo) ⇒ Array<Ryo::Object, Ryo::BasicObject>

Returns the prototype chain of a Ryo object

Parameters:

Returns:



133
134
135
136
137
138
139
140
141
# File 'lib/ryo/reflect.rb', line 133

def prototype_chain_of(ryo)
  prototypes = []
  loop do
    ryo = prototype_of(ryo)
    break unless ryo
    prototypes.push(ryo)
  end
  prototypes
end

#table_of(ryo, recursive: false) ⇒ Hash

Returns the table of a Ryo object

Parameters:

  • ryo (<Ryo::Object, Ryo::BasicObject>)

    A Ryo object

  • recursive (Boolean) (defaults to: false)

    When true, nested Ryo objects are replaced by their table as well

Returns:

  • (Hash)

    Returns the table of a Ryo object



151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/ryo/reflect.rb', line 151

def table_of(ryo, recursive: false)
  table = kernel(:instance_variable_get).bind_call(ryo, :@_table)
  if recursive
    table.each do |key, value|
      if ryo?(value)
        table[key] = table_of(value, recursive:)
      elsif value.respond_to?(:each)
        table[key] = value.respond_to?(:each_pair) ?
                     value : value.map { table_of(_1, recursive:) }
      end
    end
  end
  table
end

#set_table_of(ryo, table) ⇒ nil

Sets the table of a Ryo object

Parameters:

Returns:

  • (nil)


174
175
176
177
178
# File 'lib/ryo/reflect.rb', line 174

def set_table_of(ryo, table)
  kernel(:instance_variable_set)
    .bind_call(ryo, :@_table, table)
  nil
end

#call_method(ryo, method, *args, &b) ⇒ ::Object, ::BasicObject

Parameters:

  • ryo (<Ryo::Object, Ryo::BasicObject>)

    A Ryo object

  • method (<String, Symbol>)

    The name of a method

  • args (::Object, ::BasicObject)

    Zero or more method arguments

  • b (Proc)

    An optional block

Returns:

  • (::Object, ::BasicObject)


190
191
192
193
# File 'lib/ryo/reflect.rb', line 190

def call_method(ryo, method, *args, &b)
  kernel(:__send__)
    .bind_call(ryo, method, *args, &b)
end

#class_of(ryo) ⇒ Class

Returns the class of a Ryo object

Parameters:

Returns:

  • (Class)

    Returns the class of a Ryo object



200
201
202
# File 'lib/ryo/reflect.rb', line 200

def class_of(ryo)
  kernel(:class).bind_call(ryo)
end

#function?(obj) ⇒ Boolean

Returns true when given a Ryo function

Parameters:

Returns:

  • (Boolean)

    Returns true when given a Ryo function



209
210
211
# File 'lib/ryo/reflect.rb', line 209

def function?(obj)
  Ryo::Function === obj
end

#memo?(obj) ⇒ Boolean Also known as: lazy?

Returns true when given a Ryo memo

Parameters:

Returns:

  • (Boolean)

    Returns true when given a Ryo memo



218
219
220
# File 'lib/ryo/reflect.rb', line 218

def memo?(obj)
  Ryo::Memo === obj
end

#ryo?(obj) ⇒ Boolean

Returns true when given a Ryo object

Examples:

Ryo.ryo?(Ryo::Object(x: 5, y: 12))       # => true
Ryo.ryo?(Ryo::BasicObject(x: 10, y: 20)) # => true
Ryo.ryo?(Object.new) # => false

Parameters:

Returns:

  • (Boolean)

    Returns true when given a Ryo object



233
234
235
# File 'lib/ryo/reflect.rb', line 233

def ryo?(obj)
  Ryo === obj
end

#equal?(ryo1, ryo2) ⇒ Boolean

Returns true when the two Ryo objects are strictly equal

Parameters:

Returns:

  • (Boolean)

    Returns true when the two Ryo objects are strictly equal



244
245
246
# File 'lib/ryo/reflect.rb', line 244

def equal?(ryo1, ryo2)
  kernel(:equal?).bind_call(ryo1, ryo2)
end

#prototype_of(ryo) ⇒ Ryo?

Equivalent to JavaScript’s Reflect.getPrototypeOf

Parameters:

  • ryo (Ryo)

    A Ryo object.

Returns:

  • (Ryo, nil)

    Returns the prototype of the ryo object.



28
29
30
31
# File 'lib/ryo/reflect.rb', line 28

def prototype_of(ryo)
  kernel(:instance_variable_get)
    .bind_call(ryo, :@_proto)
end