scale.rb 0.2.1 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/.dockerignore +11 -0
- data/Dockerfile +9 -6
- data/Gemfile.lock +7 -7
- data/README.md +8 -5
- data/lib/metadata/metadata.rb +33 -28
- data/lib/metadata/metadata_v0.rb +3 -3
- data/lib/metadata/metadata_v1.rb +8 -8
- data/lib/metadata/metadata_v10.rb +1 -1
- data/lib/metadata/metadata_v11.rb +1 -1
- data/lib/metadata/metadata_v2.rb +1 -1
- data/lib/metadata/metadata_v3.rb +1 -1
- data/lib/metadata/metadata_v4.rb +7 -7
- data/lib/metadata/metadata_v5.rb +7 -7
- data/lib/metadata/metadata_v6.rb +2 -2
- data/lib/metadata/metadata_v7.rb +9 -9
- data/lib/metadata/metadata_v8.rb +2 -2
- data/lib/metadata/metadata_v9.rb +1 -1
- data/lib/scale.rb +77 -77
- data/lib/scale/base.rb +55 -20
- data/lib/scale/block.rb +120 -7
- data/lib/scale/types.rb +25 -1
- data/lib/scale/version.rb +1 -1
- data/lib/type_registry/certifybook-chain.json +10 -0
- data/lib/type_registry/darwinia.json +7 -0
- data/lib/type_registry/default.json +3713 -290
- data/lib/type_registry/kulupu.json +11 -2
- data/lib/type_registry/kusama.json +160 -18
- data/lib/type_registry/polkadot.json +85 -0
- data/lib/type_registry/westend.json +48 -3
- data/scripts/block_events.rb +34 -0
- data/scripts/example.rb +4 -0
- metadata +7 -2
    
        data/lib/metadata/metadata_v7.rb
    CHANGED
    
    | @@ -37,7 +37,7 @@ module Scale | |
| 37 37 |  | 
| 38 38 | 
             
                      if m[:events]
         | 
| 39 39 | 
             
                        m[:events].each_with_index do |event, index|
         | 
| 40 | 
            -
                          event[:lookup] = "%02x%02x" % [ | 
| 40 | 
            +
                          event[:lookup] = "%02x%02x" % [event_module_index, index]
         | 
| 41 41 | 
             
                          result.event_index[event[:lookup]] = [m, event]
         | 
| 42 42 | 
             
                        end
         | 
| 43 43 | 
             
                        event_module_index += 1
         | 
| @@ -106,14 +106,14 @@ module Scale | |
| 106 106 | 
             
                    storage_function_type = Scale::Types.type_of("Enum", %w[Plain Map DoubleMap]).decode(scale_bytes).value
         | 
| 107 107 | 
             
                    if storage_function_type == "Plain"
         | 
| 108 108 | 
             
                      result[:type] = {
         | 
| 109 | 
            -
                        Plain:  | 
| 109 | 
            +
                        Plain: String.decode(scale_bytes).value
         | 
| 110 110 | 
             
                      }
         | 
| 111 111 | 
             
                    elsif storage_function_type == "Map"
         | 
| 112 112 | 
             
                      result[:type] = {
         | 
| 113 113 | 
             
                        Map: {
         | 
| 114 114 | 
             
                          hasher: StorageHasher.decode(scale_bytes).value,
         | 
| 115 | 
            -
                          key:  | 
| 116 | 
            -
                          value:  | 
| 115 | 
            +
                          key: String.decode(scale_bytes).value,
         | 
| 116 | 
            +
                          value: String.decode(scale_bytes).value,
         | 
| 117 117 | 
             
                          linked: Bool.decode(scale_bytes).value
         | 
| 118 118 | 
             
                        }
         | 
| 119 119 | 
             
                      }
         | 
| @@ -121,16 +121,16 @@ module Scale | |
| 121 121 | 
             
                      result[:type] = {
         | 
| 122 122 | 
             
                        DoubleMap: {
         | 
| 123 123 | 
             
                          hasher: StorageHasher.decode(scale_bytes).value,
         | 
| 124 | 
            -
                          key1:  | 
| 125 | 
            -
                          key2:  | 
| 126 | 
            -
                          value:  | 
| 124 | 
            +
                          key1: String.decode(scale_bytes).value,
         | 
| 125 | 
            +
                          key2: String.decode(scale_bytes).value,
         | 
| 126 | 
            +
                          value: String.decode(scale_bytes).value,
         | 
| 127 127 | 
             
                          key2Hasher: StorageHasher.decode(scale_bytes).value
         | 
| 128 128 | 
             
                        }
         | 
| 129 129 | 
             
                      }
         | 
| 130 130 | 
             
                    end
         | 
| 131 131 |  | 
| 132 132 | 
             
                    result[:fallback] = Hex.decode(scale_bytes).value
         | 
| 133 | 
            -
                    result[: | 
| 133 | 
            +
                    result[:documentation] = Scale::Types.type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
         | 
| 134 134 |  | 
| 135 135 | 
             
                    MetadataV7ModuleStorageEntry.new(result)
         | 
| 136 136 | 
             
                  end
         | 
| @@ -143,7 +143,7 @@ module Scale | |
| 143 143 | 
             
                      name: String.decode(scale_bytes).value,
         | 
| 144 144 | 
             
                      type: String.decode(scale_bytes).value, # convert
         | 
| 145 145 | 
             
                      value: Hex.decode(scale_bytes).value,
         | 
| 146 | 
            -
                       | 
| 146 | 
            +
                      documentation: Scale::Types.type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
         | 
| 147 147 | 
             
                    }
         | 
| 148 148 | 
             
                    MetadataV7ModuleConstants.new result
         | 
| 149 149 | 
             
                  end
         | 
    
        data/lib/metadata/metadata_v8.rb
    CHANGED
    
    | @@ -37,7 +37,7 @@ module Scale | |
| 37 37 |  | 
| 38 38 | 
             
                      if m[:events]
         | 
| 39 39 | 
             
                        m[:events].each_with_index do |event, index|
         | 
| 40 | 
            -
                          event[:lookup] = "%02x%02x" % [ | 
| 40 | 
            +
                          event[:lookup] = "%02x%02x" % [event_module_index, index]
         | 
| 41 41 | 
             
                          result.event_index[event[:lookup]] = [m, event]
         | 
| 42 42 | 
             
                        end
         | 
| 43 43 | 
             
                        event_module_index += 1
         | 
| @@ -88,7 +88,7 @@ module Scale | |
| 88 88 | 
             
                  def self.decode(scale_bytes)
         | 
| 89 89 | 
             
                    result = {
         | 
| 90 90 | 
             
                      name: String.decode(scale_bytes).value,
         | 
| 91 | 
            -
                       | 
| 91 | 
            +
                      documentation: Scale::Types.type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
         | 
| 92 92 | 
             
                    }
         | 
| 93 93 |  | 
| 94 94 | 
             
                    MetadataModuleError.new(result)
         | 
    
        data/lib/metadata/metadata_v9.rb
    CHANGED
    
    | @@ -37,7 +37,7 @@ module Scale | |
| 37 37 |  | 
| 38 38 | 
             
                      if m[:events]
         | 
| 39 39 | 
             
                        m[:events].each_with_index do |event, index|
         | 
| 40 | 
            -
                          event[:lookup] = "%02x%02x" % [ | 
| 40 | 
            +
                          event[:lookup] = "%02x%02x" % [event_module_index, index]
         | 
| 41 41 | 
             
                          result.event_index[event[:lookup]] = [m, event]
         | 
| 42 42 | 
             
                        end
         | 
| 43 43 | 
             
                        event_module_index += 1
         | 
    
        data/lib/scale.rb
    CHANGED
    
    | @@ -29,89 +29,78 @@ module Scale | |
| 29 29 |  | 
| 30 30 | 
             
              class TypeRegistry
         | 
| 31 31 | 
             
                include Singleton
         | 
| 32 | 
            -
                 | 
| 32 | 
            +
                attr_reader :spec_name, :types, :versioning, :custom_types
         | 
| 33 | 
            +
                attr_accessor :spec_version
         | 
| 34 | 
            +
                attr_accessor :metadata
         | 
| 33 35 |  | 
| 34 | 
            -
                def load(spec_name  | 
| 35 | 
            -
                  @spec_name =  | 
| 36 | 
            -
                  @ | 
| 37 | 
            -
                  @ | 
| 36 | 
            +
                def load(spec_name: nil, custom_types: nil)
         | 
| 37 | 
            +
                  @spec_name = nil
         | 
| 38 | 
            +
                  @types = nil
         | 
| 39 | 
            +
                  @versioning = nil
         | 
| 40 | 
            +
                  @custom_types = nil
         | 
| 38 41 |  | 
| 42 | 
            +
                  default_types, _, _ = load_chain_spec_types("default")
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  if spec_name.nil? || spec_name == "default"
         | 
| 45 | 
            +
                    @spec_name = "default"
         | 
| 46 | 
            +
                    @types = default_types
         | 
| 47 | 
            +
                  else
         | 
| 48 | 
            +
                    @spec_name = spec_name
         | 
| 49 | 
            +
                    spec_types, @versioning, @spec_version = load_chain_spec_types(spec_name)
         | 
| 50 | 
            +
                    @types = default_types.merge(spec_types)
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  self.custom_types = custom_types
         | 
| 39 54 | 
             
                  true
         | 
| 40 55 | 
             
                end
         | 
| 41 56 |  | 
| 42 57 | 
             
                def get(type_name)
         | 
| 43 | 
            -
                   | 
| 44 | 
            -
                  return Scale::Types.type_of(type_name) if type.nil?
         | 
| 45 | 
            -
                  type
         | 
| 46 | 
            -
                end
         | 
| 58 | 
            +
                  raise "Types not loaded" if @types.nil?
         | 
| 47 59 |  | 
| 48 | 
            -
             | 
| 49 | 
            -
                def load_types(spec_name, spec_version)
         | 
| 50 | 
            -
                  # hard coded types
         | 
| 51 | 
            -
                  coded_types = Scale::Types
         | 
| 52 | 
            -
                    .constants
         | 
| 53 | 
            -
                    .select { |c| Scale::Types.const_get(c).is_a? Class }
         | 
| 54 | 
            -
                    .map { |type_name| [type_name.to_s, type_name.to_s] }
         | 
| 55 | 
            -
                    .to_h
         | 
| 56 | 
            -
                    .transform_values {|type| Scale::Types.constantize(type) }
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                  return coded_types if spec_name.nil?
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                  # default spec types
         | 
| 61 | 
            -
                  default_types = load_chain_spec_types("default", spec_version).transform_values do |type|
         | 
| 62 | 
            -
                    Scale::Types.type_convert(type, coded_types)
         | 
| 63 | 
            -
                  end
         | 
| 64 | 
            -
                  default_types = coded_types.merge(default_types)
         | 
| 60 | 
            +
                  all_types = {}.merge(@types)
         | 
| 65 61 |  | 
| 66 | 
            -
                   | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
                       | 
| 62 | 
            +
                  if @spec_version && @versioning
         | 
| 63 | 
            +
                    @versioning.each do |item|
         | 
| 64 | 
            +
                      if @spec_version >= item["runtime_range"][0] && @spec_version <= (item["runtime_range"][1] || 1073741823)
         | 
| 65 | 
            +
                        all_types.merge!(item["types"])
         | 
| 66 | 
            +
                      end
         | 
| 71 67 | 
             
                    end
         | 
| 72 | 
            -
                    default_types.merge(spec_types)
         | 
| 73 | 
            -
                  else
         | 
| 74 | 
            -
                    default_types
         | 
| 75 68 | 
             
                  end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  all_types.merge!(@custom_types) if @custom_types
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  type = type_traverse(type_name, all_types)
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  Scale::Types.constantize(type)
         | 
| 76 75 | 
             
                end
         | 
| 77 76 |  | 
| 78 | 
            -
                def  | 
| 79 | 
            -
                   | 
| 80 | 
            -
             | 
| 81 | 
            -
                  json = JSON.parse(json_string)
         | 
| 77 | 
            +
                def custom_types=(custom_types)
         | 
| 78 | 
            +
                  @custom_types = custom_types.stringify_keys if (not custom_types.nil?) && custom_types.class.name == "Hash"
         | 
| 79 | 
            +
                end
         | 
| 82 80 |  | 
| 83 | 
            -
             | 
| 84 | 
            -
                  runtime_id = json["runtime_id"]
         | 
| 85 | 
            -
                  versioning = json["versioning"] || []
         | 
| 81 | 
            +
                private
         | 
| 86 82 |  | 
| 87 | 
            -
                   | 
| 88 | 
            -
                     | 
| 89 | 
            -
             | 
| 83 | 
            +
                  def load_chain_spec_types(spec_name)
         | 
| 84 | 
            +
                    file = File.join File.expand_path("../..", __FILE__), "lib", "type_registry", "#{spec_name}.json"
         | 
| 85 | 
            +
                    json_string = File.open(file).read
         | 
| 86 | 
            +
                    json = JSON.parse(json_string)
         | 
| 90 87 |  | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
                        types.merge!(item["types"])
         | 
| 95 | 
            -
                      end
         | 
| 96 | 
            -
                    end
         | 
| 88 | 
            +
                    runtime_id = json["runtime_id"]
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                    [json["types"], json["versioning"], runtime_id]
         | 
| 97 91 | 
             
                  end
         | 
| 98 92 |  | 
| 99 | 
            -
                   | 
| 100 | 
            -
                    if type | 
| 101 | 
            -
                       | 
| 93 | 
            +
                  def type_traverse(type, types)
         | 
| 94 | 
            +
                    if types.has_key?(type)
         | 
| 95 | 
            +
                      type_traverse(types[type], types)
         | 
| 102 96 | 
             
                    else
         | 
| 103 | 
            -
                       | 
| 104 | 
            -
             | 
| 105 | 
            -
                        Scale::Types.constantize(t)
         | 
| 97 | 
            +
                      if type.class == ::String
         | 
| 98 | 
            +
                        rename(type)
         | 
| 106 99 | 
             
                      else
         | 
| 107 | 
            -
                         | 
| 100 | 
            +
                        type
         | 
| 108 101 | 
             
                      end
         | 
| 109 102 | 
             
                    end
         | 
| 110 103 | 
             
                  end
         | 
| 111 | 
            -
             | 
| 112 | 
            -
                  types
         | 
| 113 | 
            -
                end
         | 
| 114 | 
            -
             | 
| 115 104 | 
             
              end
         | 
| 116 105 |  | 
| 117 106 | 
             
              # TODO: == implement
         | 
| @@ -227,7 +216,6 @@ module Scale | |
| 227 216 | 
             
                end
         | 
| 228 217 |  | 
| 229 218 | 
             
                def self.get(type_name)
         | 
| 230 | 
            -
                  type_name = adjust(type_name)
         | 
| 231 219 | 
             
                  TypeRegistry.instance.get(type_name)
         | 
| 232 220 | 
             
                end
         | 
| 233 221 |  | 
| @@ -247,19 +235,6 @@ module Scale | |
| 247 235 | 
             
                  end
         | 
| 248 236 | 
             
                end
         | 
| 249 237 |  | 
| 250 | 
            -
                def self.type_convert(type, types)
         | 
| 251 | 
            -
                  return type if type.class != ::String
         | 
| 252 | 
            -
             | 
| 253 | 
            -
                  if type =~ /\[u\d+; \d+\]/
         | 
| 254 | 
            -
                    byte_length = type.scan(/\[u\d+; (\d+)\]/).first.first
         | 
| 255 | 
            -
                    "VecU8Length#{byte_length}"
         | 
| 256 | 
            -
                  elsif types.has_key?(type) && types[type] != type
         | 
| 257 | 
            -
                    type_convert(types[type], types)
         | 
| 258 | 
            -
                  else
         | 
| 259 | 
            -
                    adjust(type)
         | 
| 260 | 
            -
                  end
         | 
| 261 | 
            -
                end
         | 
| 262 | 
            -
             | 
| 263 238 | 
             
                def self.type_of(type_string, values = nil)
         | 
| 264 239 | 
             
                  if type_string.end_with?(">")
         | 
| 265 240 | 
             
                    type_strs = type_string.scan(/^([^<]*)<(.+)>$/).first
         | 
| @@ -274,7 +249,7 @@ module Scale | |
| 274 249 | 
             
                      name = "#{type_str}_Of_#{inner_type_str.camelize}_#{klass.object_id}"
         | 
| 275 250 | 
             
                      Scale::Types.const_set fix(name), klass
         | 
| 276 251 | 
             
                    else
         | 
| 277 | 
            -
                      raise "#{type_str} not support inner type"
         | 
| 252 | 
            +
                      raise "#{type_str} not support inner type: #{type_string}"
         | 
| 278 253 | 
             
                    end
         | 
| 279 254 | 
             
                  elsif type_string.start_with?("(") && type_string.end_with?(")") # tuple
         | 
| 280 255 | 
             
                    # TODO: add nested tuple support
         | 
| @@ -345,13 +320,14 @@ def fix(name) | |
| 345 320 | 
             
                .gsub(":", "։")
         | 
| 346 321 | 
             
            end
         | 
| 347 322 |  | 
| 348 | 
            -
            def  | 
| 323 | 
            +
            def rename(type)
         | 
| 349 324 | 
             
              type = type.gsub("T::", "")
         | 
| 350 325 | 
             
                .gsub("<T>", "")
         | 
| 351 326 | 
             
                .gsub("<T as Trait>::", "")
         | 
| 352 327 | 
             
                .delete("\n")
         | 
| 353 328 | 
             
                .gsub("EventRecord<Event, Hash>", "EventRecord")
         | 
| 354 329 | 
             
                .gsub(/(u)(\d+)/, 'U\2')
         | 
| 330 | 
            +
              return "Bool" if type == "bool"
         | 
| 355 331 | 
             
              return "Null" if type == "()"
         | 
| 356 332 | 
             
              return "String" if type == "Vec<u8>"
         | 
| 357 333 | 
             
              return "Compact" if type == "Compact<u32>" || type == "Compact<U32>"
         | 
| @@ -360,9 +336,17 @@ def adjust(type) | |
| 360 336 | 
             
              return "Compact" if type == "<Balance as HasCompact>::Type"
         | 
| 361 337 | 
             
              return "Compact" if type == "<BlockNumber as HasCompact>::Type"
         | 
| 362 338 | 
             
              return "Compact" if type == "Compact<Balance>"
         | 
| 339 | 
            +
              return "Compact" if type == "Compact<BlockNumber>"
         | 
| 363 340 | 
             
              return "CompactMoment" if type == "<Moment as HasCompact>::Type"
         | 
| 341 | 
            +
              return "CompactMoment" if type == "Compact<Moment>"
         | 
| 364 342 | 
             
              return "InherentOfflineReport" if type == "<InherentOfflineReport as InherentOfflineReport>::Inherent"
         | 
| 365 343 | 
             
              return "AccountData" if type == "AccountData<Balance>"
         | 
| 344 | 
            +
             | 
| 345 | 
            +
              if type =~ /\[U\d+; \d+\]/
         | 
| 346 | 
            +
                byte_length = type.scan(/\[U\d+; (\d+)\]/).first.first
         | 
| 347 | 
            +
                return "VecU8Length#{byte_length}"
         | 
| 348 | 
            +
              end
         | 
| 349 | 
            +
             | 
| 366 350 | 
             
              type
         | 
| 367 351 | 
             
            end
         | 
| 368 352 |  | 
| @@ -395,3 +379,19 @@ class Integer | |
| 395 379 | 
             
                self
         | 
| 396 380 | 
             
              end
         | 
| 397 381 | 
             
            end
         | 
| 382 | 
            +
             | 
| 383 | 
            +
            class ::Hash
         | 
| 384 | 
            +
              # via https://stackoverflow.com/a/25835016/2257038
         | 
| 385 | 
            +
              def stringify_keys
         | 
| 386 | 
            +
                h = self.map do |k,v|
         | 
| 387 | 
            +
                  v_str = if v.instance_of? Hash
         | 
| 388 | 
            +
                            v.stringify_keys
         | 
| 389 | 
            +
                          else
         | 
| 390 | 
            +
                            v
         | 
| 391 | 
            +
                          end
         | 
| 392 | 
            +
             | 
| 393 | 
            +
                  [k.to_s, v_str]
         | 
| 394 | 
            +
                end
         | 
| 395 | 
            +
                Hash[h]
         | 
| 396 | 
            +
              end
         | 
| 397 | 
            +
            end
         | 
    
        data/lib/scale/base.rb
    CHANGED
    
    | @@ -11,6 +11,28 @@ module Scale | |
| 11 11 | 
             
                  def ==(other)
         | 
| 12 12 | 
             
                    value == other.value
         | 
| 13 13 | 
             
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def to_human
         | 
| 16 | 
            +
                    if @value.class == ::Hash
         | 
| 17 | 
            +
                      @value.transform_values do |v|
         | 
| 18 | 
            +
                        if v.class.included_modules.include?(SingleValue)
         | 
| 19 | 
            +
                          v.to_human
         | 
| 20 | 
            +
                        else
         | 
| 21 | 
            +
                          v
         | 
| 22 | 
            +
                        end
         | 
| 23 | 
            +
                      end
         | 
| 24 | 
            +
                    elsif @value.class == ::Array
         | 
| 25 | 
            +
                      @value.map do |v|
         | 
| 26 | 
            +
                        if v.class.included_modules.include?(SingleValue)
         | 
| 27 | 
            +
                          v.to_human
         | 
| 28 | 
            +
                        else
         | 
| 29 | 
            +
                          v
         | 
| 30 | 
            +
                        end
         | 
| 31 | 
            +
                      end
         | 
| 32 | 
            +
                    else
         | 
| 33 | 
            +
                      @value
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
                  end
         | 
| 14 36 | 
             
                end
         | 
| 15 37 |  | 
| 16 38 | 
             
                # value: one of nil, false, true, scale object
         | 
| @@ -67,9 +89,8 @@ module Scale | |
| 67 89 |  | 
| 68 90 | 
             
                  module ClassMethods
         | 
| 69 91 | 
             
                    def decode(scale_bytes)
         | 
| 70 | 
            -
                       | 
| 71 | 
            -
                       | 
| 72 | 
            -
                      bytes = scale_bytes.get_next_bytes byte_length
         | 
| 92 | 
            +
                      bytes = scale_bytes.get_next_bytes self::BYTE_LENGTH
         | 
| 93 | 
            +
                      bit_length = bytes.length.to_i * 8
         | 
| 73 94 | 
             
                      value = bytes.reverse.bytes_to_hex.to_i(16).to_signed(bit_length)
         | 
| 74 95 | 
             
                      new(value)
         | 
| 75 96 | 
             
                    end
         | 
| @@ -83,7 +104,7 @@ module Scale | |
| 83 104 | 
             
                    if value.class != ::Integer
         | 
| 84 105 | 
             
                      raise "#{self.class}'s value must be integer"
         | 
| 85 106 | 
             
                    end
         | 
| 86 | 
            -
                    bit_length = self.class | 
| 107 | 
            +
                    bit_length = self.class::BYTE_LENGTH * 8
         | 
| 87 108 | 
             
                    hex = value.to_unsigned(bit_length).to_s(16).hex_to_bytes.reverse.bytes_to_hex
         | 
| 88 109 | 
             
                    hex[2..]
         | 
| 89 110 | 
             
                  end
         | 
| @@ -111,19 +132,20 @@ module Scale | |
| 111 132 | 
             
                    if value.class != ::Integer
         | 
| 112 133 | 
             
                      raise "#{self.class}'s value must be integer"
         | 
| 113 134 | 
             
                    end
         | 
| 114 | 
            -
                     | 
| 135 | 
            +
                    byte_length = self.class::BYTE_LENGTH
         | 
| 136 | 
            +
                    bytes = value.to_s(16).rjust(byte_length * 2, "0").scan(/.{2}/).reverse.map {|hex| hex.to_i(16) }
         | 
| 115 137 | 
             
                    bytes.bytes_to_hex[2..]
         | 
| 116 138 | 
             
                  end
         | 
| 117 139 | 
             
                end
         | 
| 118 140 |  | 
| 119 | 
            -
             | 
| 120 141 | 
             
                module Struct
         | 
| 121 142 | 
             
                  include SingleValue
         | 
| 122 143 | 
             
                  # new(1.to_u32, U32(69))
         | 
| 123 144 | 
             
                  module ClassMethods
         | 
| 124 145 | 
             
                    def decode(scale_bytes)
         | 
| 125 146 | 
             
                      item_values = self::ITEM_TYPE_STRS.map do |item_type_str|
         | 
| 126 | 
            -
                        Scale:: | 
| 147 | 
            +
                        type = Scale::TypeRegistry.instance.get(item_type_str)
         | 
| 148 | 
            +
                        type.decode(scale_bytes)
         | 
| 127 149 | 
             
                      end
         | 
| 128 150 |  | 
| 129 151 | 
             
                      value = {}
         | 
| @@ -197,7 +219,7 @@ module Scale | |
| 197 219 | 
             
                  module ClassMethods
         | 
| 198 220 | 
             
                    def decode(scale_bytes)
         | 
| 199 221 | 
             
                      index = scale_bytes.get_next_bytes(1)[0]
         | 
| 200 | 
            -
                      if const_defined? " | 
| 222 | 
            +
                      if const_defined? "ITEM_TYPE_STRS"
         | 
| 201 223 | 
             
                        item_type_str = self::ITEM_TYPE_STRS[index]
         | 
| 202 224 | 
             
                        raise "There is no such member with index #{index} for enum #{self}" if item_type_str.nil?
         | 
| 203 225 | 
             
                        value = Scale::Types.get(item_type_str).decode(scale_bytes)
         | 
| @@ -208,16 +230,20 @@ module Scale | |
| 208 230 | 
             
                    end
         | 
| 209 231 |  | 
| 210 232 | 
             
                    def items(items)
         | 
| 211 | 
            -
                       | 
| 212 | 
            -
             | 
| 233 | 
            +
                      if items.class == ::Hash
         | 
| 234 | 
            +
                        attr_names = []
         | 
| 235 | 
            +
                        attr_type_strs = []
         | 
| 213 236 |  | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 237 | 
            +
                        items.each_pair do |attr_name, attr_type_str|
         | 
| 238 | 
            +
                          attr_names << attr_name
         | 
| 239 | 
            +
                          attr_type_strs << attr_type_str
         | 
| 240 | 
            +
                        end
         | 
| 218 241 |  | 
| 219 | 
            -
             | 
| 220 | 
            -
             | 
| 242 | 
            +
                        const_set(:ITEM_NAMES, attr_names)
         | 
| 243 | 
            +
                        const_set(:ITEM_TYPE_STRS, attr_type_strs)
         | 
| 244 | 
            +
                      elsif items.class == ::Array
         | 
| 245 | 
            +
                        const_set(:ITEM_TYPE_STRS, items)
         | 
| 246 | 
            +
                      end
         | 
| 221 247 | 
             
                    end
         | 
| 222 248 |  | 
| 223 249 | 
             
                    def values(*values)
         | 
| @@ -238,6 +264,14 @@ module Scale | |
| 238 264 | 
             
                      self.class::VALUES.index(value).to_s(16).rjust(2, "0")
         | 
| 239 265 | 
             
                    end
         | 
| 240 266 | 
             
                  end
         | 
| 267 | 
            +
             | 
| 268 | 
            +
                  def to_human
         | 
| 269 | 
            +
                    if self.class.const_defined? "ITEM_TYPE_STRS"
         | 
| 270 | 
            +
                      @value.to_human
         | 
| 271 | 
            +
                    else
         | 
| 272 | 
            +
                      @value
         | 
| 273 | 
            +
                    end
         | 
| 274 | 
            +
                  end
         | 
| 241 275 | 
             
                end
         | 
| 242 276 |  | 
| 243 277 | 
             
                module Vec
         | 
| @@ -248,7 +282,8 @@ module Scale | |
| 248 282 | 
             
                      number = Scale::Types::Compact.decode(scale_bytes).value
         | 
| 249 283 | 
             
                      items = []
         | 
| 250 284 | 
             
                      number.times do
         | 
| 251 | 
            -
                         | 
| 285 | 
            +
                        type = Scale::Types.get(self::INNER_TYPE_STR)
         | 
| 286 | 
            +
                        item = type.decode(scale_bytes)
         | 
| 252 287 | 
             
                        items << item
         | 
| 253 288 | 
             
                      end
         | 
| 254 289 | 
             
                      raw ? items : new(items)
         | 
| @@ -278,7 +313,7 @@ module Scale | |
| 278 313 |  | 
| 279 314 | 
             
                  module ClassMethods
         | 
| 280 315 | 
             
                    def decode(scale_bytes)
         | 
| 281 | 
            -
                      value = "Scale::Types::U#{self:: | 
| 316 | 
            +
                      value = "Scale::Types::U#{self::BYTE_LENGTH * 8}".constantize.decode(scale_bytes).value
         | 
| 282 317 | 
             
                      return new [] unless value || value <= 0
         | 
| 283 318 |  | 
| 284 319 | 
             
                      result = self::ITEMS.select { |_, mask| value & mask > 0 }.keys
         | 
| @@ -295,7 +330,7 @@ module Scale | |
| 295 330 | 
             
                    def items(items, bytes_length = 1)
         | 
| 296 331 | 
             
                      raise "byte length is wrong: #{bytes_length}" unless [1, 2, 4, 8, 16].include?(bytes_length)
         | 
| 297 332 | 
             
                      const_set(:ITEMS, items)
         | 
| 298 | 
            -
                      const_set(: | 
| 333 | 
            +
                      const_set(:BYTE_LENGTH, bytes_length)
         | 
| 299 334 | 
             
                    end
         | 
| 300 335 | 
             
                  end
         | 
| 301 336 |  | 
| @@ -305,7 +340,7 @@ module Scale | |
| 305 340 |  | 
| 306 341 | 
             
                  def encode
         | 
| 307 342 | 
             
                    value = self.class::ITEMS.select { |key, _| self.value.include?(key) }.values.sum
         | 
| 308 | 
            -
                    "Scale::Types::U#{self.class:: | 
| 343 | 
            +
                    "Scale::Types::U#{self.class::BYTE_LENGTH * 8}".constantize.new(value).encode
         | 
| 309 344 | 
             
                  end
         | 
| 310 345 | 
             
                end
         | 
| 311 346 |  |