Class: Jsof::WrapObject

Inherits:
Object
  • Object
show all
Defined in:
lib/jsof/wrap_object.rb

Overview

Wrapper class for Object(Hash).

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(obj = {}, allow_implicit_attr: nil) ⇒ WrapObject

Create wrapper for Hash.

Parameters:

  • obj (Hash) (defaults to: {})

    Wrap target hash

  • allow_implicit_attr (Boolean) (defaults to: nil)

    Allow to use undefined properties or not. If nil, assume true if it’s instance of WrapObject, and assume false if it’s instance of derived classes.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/jsof/wrap_object.rb', line 9

def initialize(obj = {}, allow_implicit_attr: nil)
  unless self.class.initialized?
    self.class.resolve_typeof_properties
    self.class.initialize()
    self.class.initialized = true
  end

  @internal_object = obj
  @wrapped = {}
  @is_allow_implicit_attr = allow_implicit_attr
  if @is_allow_implicit_attr == nil
    @is_allow_implicit_attr = self.class.typeof_properties.empty?
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

Raises:

  • (NoMethodError)


115
116
117
118
119
120
121
122
123
# File 'lib/jsof/wrap_object.rb', line 115

def method_missing(name, *args)
  raise NoMethodError.new("", name) unless @is_allow_implicit_attr

  if name.to_s.end_with?('=')
    self[name.to_s[0...-1].to_sym] = args.first
  else
    self[name]
  end
end

Class Method Details

.assignable?(val) ⇒ Boolean

Check value can be wrapped by this type. TODO: Currently, will not check properties’s types, but this behavior might be changed in future version.

Returns:

  • (Boolean)


76
77
78
79
80
81
# File 'lib/jsof/wrap_object.rb', line 76

def self.assignable?(val)
  # TODO:
  return true if val == nil
  return true if val.is_a? Hash
  false
end

.define_attr(sym, type: nil) ⇒ Object

Define explicit accessor methods for attribute(property).

Parameters:

  • sym (Symbol)

    Attribute name.

  • type (Class, Jsof::WrapArrayType, Proc) (defaults to: nil)

    If nil, the property is untyped. Usually, pass Class to specify the type of the property. If you want to specify typed Array, then pass instance of Jsof::WrapArrayType. If you want to use the class not defined yet (defined later) , then wrap with Proc like ‘->{ YourClass }`.



62
63
64
65
66
67
68
69
70
# File 'lib/jsof/wrap_object.rb', line 62

def self.define_attr(sym, type: nil)
  @typeof_properties[sym] = type
  self.define_method(sym) do
    self[sym]
  end
  self.define_method((sym.to_s + "=").to_sym) do |val|
    self[sym] = val
  end
end

.inherited(subclass) ⇒ Object



25
26
27
# File 'lib/jsof/wrap_object.rb', line 25

def self.inherited(subclass)
  subclass.instance_variable_set(:@typeof_properties, @typeof_properties.dup)
end

.initializeObject

Place to define properties by define_attr. Override this for derived class. This method will be called when the first instace is created.



51
52
53
# File 'lib/jsof/wrap_object.rb', line 51

def self.initialize
  # override
end

.initialized=(val) ⇒ Object



45
46
47
# File 'lib/jsof/wrap_object.rb', line 45

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

.initialized?Boolean

Whether self.initialize was already called or not.

Returns:

  • (Boolean)


42
43
44
# File 'lib/jsof/wrap_object.rb', line 42

def self.initialized?
  @initialized
end

.resolve_typeof_propertiesObject



33
34
35
36
37
38
39
# File 'lib/jsof/wrap_object.rb', line 33

def self.resolve_typeof_properties
  @typeof_properties.keys.each do |sym|
    if @typeof_properties[sym].is_a? Proc
      @typeof_properties[sym] = @typeof_properties[sym].call
    end
  end
end

.typeof_propertiesHash{Symbol => Class, Jsof::WrapArrayType, Proc}

Explicitly defined properties.

Returns:



30
31
32
# File 'lib/jsof/wrap_object.rb', line 30

def self.typeof_properties
  @typeof_properties
end

Instance Method Details

#[](key) ⇒ Object



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

def [](key)
  sym = key.to_sym
  return @wrapped[sym] if @wrapped.key?(sym)

  elem = @internal_object[sym]
  boxed = Jsof::WrapHelper.boxing(elem, self.class.typeof_properties[sym])
  @wrapped[sym] = boxed if elem != boxed
  return boxed
end

#[]=(key, val) ⇒ Object



98
99
100
101
102
103
104
105
106
107
# File 'lib/jsof/wrap_object.rb', line 98

def []=(key, val)
  sym = key.to_sym
  if type = self.class.typeof_properties[sym]
    raise TypeError unless Jsof::WrapHelper.assignable?(type, val)
  end
  boxed = Jsof::WrapHelper.boxing(val, self.class.typeof_properties[sym])
  @wrapped[sym] = boxed if Jsof::WrapHelper.wrapped_value?(boxed)
  @internal_object[sym] = Jsof::WrapHelper.unboxing(val)
  val
end

#clear_internalObject

Clean internal cache. Call this after you changed wrapped object directly.



111
112
113
# File 'lib/jsof/wrap_object.rb', line 111

def clear_internal
  @wrapped.clear
end

#internal_objectObject

Return reference to wrapped array.



84
85
86
# File 'lib/jsof/wrap_object.rb', line 84

def internal_object
  @internal_object
end

#to_hObject

Return reference to wrapped array.



131
132
133
# File 'lib/jsof/wrap_object.rb', line 131

def to_h
  @internal_object
end

#to_hashObject

Return reference to wrapped array.



126
127
128
# File 'lib/jsof/wrap_object.rb', line 126

def to_hash
  @internal_object
end