Class: Types::Struct

Inherits:
Typed
  • Object
show all
Defined in:
lib/solidity/typed/struct.rb,
lib/solidity/typed/struct_builder.rb

Constant Summary

Constants inherited from Typed

Typed::ADDRESS_ZERO, Typed::BYTES20_ZERO, Typed::BYTES32_ZERO, Typed::BYTES_ZERO, Typed::INSCRIPTION_ID_ZERO, Typed::STRING_ZERO

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Typed

#as_json, dump, serialize, #serialize, #type, type

Constructor Details

#initialize(*args, **kwargs) ⇒ Struct

Returns a new instance of Struct.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/solidity/typed/struct.rb', line 18

def initialize( *args, **kwargs )
   ## fix-fix-fix: first check for matching args - why? why not?
   if kwargs.size > 0   ## assume kwargs init
      self.class.attributes.each do |key, type|
         ## note: allow unused keys (will get set to zero)
         value = kwargs.has_key?( key ) ? kwargs[ key ] : type.new_zero
         value = if value.is_a?( Typed )
                   ## fix-fix-fix - check type match here!!!
                   value
                 else 
                   type.new( value )
                 end
         instance_variable_set( "@#{key}", value )
       end
   else
     self.class.attributes.zip( args ).each do |(key, type), value|
       value = if value.is_a?(Typed)
                 ## fix-fix-fix - check type match here!!!
                 value
               else 
                 type.new( value )
               end
       instance_variable_set( "@#{key}", value )
     end
   end
   self  ## note: return reference to self for chaining method calls
end

Class Method Details

.build_class(class_name, scope: Types, **attributes) ⇒ Object Also known as: new

todo/fix: scope: keep empty by default



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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
# File 'lib/solidity/typed/struct_builder.rb', line 8

def self.build_class( class_name, scope: Types, **attributes )

 ## todo/fix:
 ##    add  self.class.type  class method
 ##                returns  TypedStruct<> instance with typedef info
 ##
 ##  add name & format
 ##   e.g.  :struct (why? why not? or :tuple? if using abi names?)
 ##              tuple( types,... ) - flattend (recursive)!!! - why? why not?


 ## todo/fix:
 ## check if valid class_name MUST start with uppercase letter etc.
 ##  todo/fix: check if constant is undefined in scoped namespace!!!!

   ## map type symbols (:uint, :address, etc.)
   ##   to type for now "by hand" here

   attributes = attributes.map do |key,type|
  ##                t  =type 
                  ## t = t.type             if t.is_a?( Class ) && t.ancestors.include?( Typed )
                  [key, typeof( type )]
                end.to_h


  klass = Class.new( Struct ) do
    attributes.each do |key,type|
      define_method( key ) do
        instance_variable_get( "@#{key}" )
      end
      ## note: for Bool auto-add getter with question mark (e.g. voted? etc.)
      ##          why? why not?
      if type == BoolType.instance  
        define_method( "#{key}?" ) do
          instance_variable_get( "@#{key}" )
        end
      end
      define_method( "#{key}=" ) do |value|
        ## todo/fix:
        ## check if arg is typed && type match?
        ##  if not (assume literal) try to convert to type!!!! 

        value = if value.is_a?(Typed)
                  ## fix-fix-fix - check type match here!!!
                  value
              else 
                type.new( value )
              end

        instance_variable_set( "@#{key}", value )
      end
    end


 
    
    alias_method :old_freeze, :freeze   # note: store "old" orginal version of freeze
    define_method( :freeze ) do
      old_freeze    ## same as calling super
      attributes.keys.each do |key|
        instance_variable_get( "@#{key}" ).freeze
      end
      self   # return reference to self
    end
  end


  type = StructType.new( class_name, klass )
  klass.define_singleton_method( :type ) do
    @type ||= type       
  end

  ## add attributes (with keys / types) class method 
  klass.define_singleton_method( :attributes ) do
     attributes 
  end

  ## add self.new too - note: call/forward to "old" orginal self.new of Event (base) class
  klass.define_singleton_method( :new ) do |*args, **kwargs|
    if kwargs.size > 0  ## assume kwargs 
      ## -fix-fix-fix- check all keywords if part or struct here too!!!
      old_new( **kwargs )    
    else
      if args.empty?  ## no args - use new_zero and set (initialize) all ivars to zero
        new_zero
      else
        if args.size != attributes.size
          ## check for required args/params - all MUST be passed in!!!
          raise ArgumentError, "[Struct] wrong number of arguments for #{name}.new - #{args.size} for #{attributes.size}"
        end
        old_new( *args )
      end
    end
  end


  klass.define_singleton_method( :new_zero ) do
    values = attributes.values.map do |type|
      if type.respond_to?( :new_zero )
        type.new_zero
      else
        raise ArgumentError, "[Struct] no new_zero support for type #{type}; sorry"
      end
    end
    old_new( *values )
  end


=begin
  ## note: use Kernel for "namespacing"
  ##   make all enums convenience converters (always) global
  ##     including uppercase methods (e.g. State(), Color(), etc.) does NOT work otherwise (with other module includes)

  ## add global "Kernel" convenience converter function
  ##  e.g. Vote(0) is same as Vote.convert(0)
  Kernel.class_eval( <<RUBY )
    def #{class_name}( arg )
       #{class_name}.convert( arg )
    end
RUBY
=end

 ## note: use scoped (module) and NOT Object for namespacing
 ##   use include Safe to make all structs global
 ##  fix-fix-fix - make class_name unique across contracts (e.g. reuse same name in different contract)
  scope.const_set( class_name, klass )   ## returns klass (plus sets global constant class name)
end

.zeroObject



5
6
7
8
9
10
11
12
# File 'lib/solidity/typed/struct.rb', line 5

def self.zero
  ## note: freeze return new zero (for "singelton" & "immutable" zero instance)
  ##  todo/fix:
  ##   in build_class add freeze for composite/reference objects
  ##     that is, arrays, hash mappings, structs etc.
  ##   freeze only works for now for "value" objects e.g. integer, bool, etc.
  @zero ||= new_zero.freeze
end

Instance Method Details

#==(other) ⇒ Object



58
59
60
61
62
63
64
65
66
# File 'lib/solidity/typed/struct.rb', line 58

def ==(other)
   if other.is_a?( self.class )
      self.class.attributes.keys.all? do |key|
            __send__( key ) == other.__send__( key )
      end
   else
      false
   end
end

#as_dataObject



47
48
49
50
51
52
53
54
# File 'lib/solidity/typed/struct.rb', line 47

def as_data
   self.class.attributes.keys.map do |key|
        ivar = instance_variable_get( "@#{key}" )
        puts "  @#{key}:"
        pp ivar
        ivar.as_data
   end
end

#zero?Boolean

Returns:

  • (Boolean)


14
# File 'lib/solidity/typed/struct.rb', line 14

def zero?() self == self.class.zero; end