scale.rb 0.2.16 → 0.3.0
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/.gitignore +1 -0
- data/Cargo.lock +8 -4
- data/Cargo.toml +2 -3
- data/Dockerfile +4 -1
- data/Gemfile.lock +43 -35
- data/README.md +44 -1
- data/Rakefile +6 -0
- data/exe/scale +39 -79
- data/lib/address.rb +3 -0
- data/lib/common.rb +163 -0
- data/lib/helper.rb +25 -8
- data/lib/metadata/metadata.rb +28 -18
- data/lib/metadata/metadata_v0.rb +24 -20
- data/lib/metadata/metadata_v1.rb +13 -9
- data/lib/metadata/metadata_v10.rb +2 -2
- data/lib/metadata/metadata_v11.rb +2 -2
- data/lib/metadata/metadata_v12.rb +9 -8
- data/lib/metadata/metadata_v13.rb +161 -0
- data/lib/metadata/metadata_v2.rb +2 -2
- data/lib/metadata/metadata_v3.rb +2 -2
- data/lib/metadata/metadata_v4.rb +21 -11
- data/lib/metadata/metadata_v5.rb +21 -11
- data/lib/metadata/metadata_v6.rb +9 -9
- data/lib/metadata/metadata_v7.rb +26 -15
- data/lib/metadata/metadata_v8.rb +9 -9
- data/lib/metadata/metadata_v9.rb +2 -2
- data/lib/scale.rb +41 -341
- data/lib/scale/base.rb +177 -95
- data/lib/scale/block.rb +17 -13
- data/lib/scale/trie.rb +1 -1
- data/lib/scale/types.rb +139 -40
- data/lib/scale/version.rb +1 -1
- data/lib/scale_bytes.rb +63 -0
- data/lib/substrate_client.rb +31 -17
- data/lib/type_builder.rb +279 -0
- data/lib/type_registry.rb +91 -0
- data/lib/type_registry/crab.json +676 -595
- data/lib/type_registry/darwinia.json +730 -554
- data/lib/type_registry/default.json +3 -2
- data/lib/type_registry/pangolin.json +771 -0
- data/scale.gemspec +7 -5
- data/scripts/mmr_root_to_sign.rb +10 -0
- data/src/lib.rs +80 -25
- metadata +59 -30
- data/lib/type_registry/edgeware.json +0 -124
- data/lib/type_registry/joystream.json +0 -49
- data/lib/type_registry/kulupu.json +0 -15
- data/lib/type_registry/plasm.json +0 -89
- data/lib/type_registry/robonomics.json +0 -39
- data/lib/type_registry/westend.json +0 -63
- data/src/storage_key.rs +0 -41
data/lib/metadata/metadata_v8.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Scale
|
2
2
|
module Types
|
3
3
|
class MetadataV8
|
4
|
-
include
|
4
|
+
include Base
|
5
5
|
attr_accessor :call_index, :event_index
|
6
6
|
|
7
7
|
def initialize(value)
|
@@ -11,7 +11,7 @@ module Scale
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.decode(scale_bytes)
|
14
|
-
modules = Scale::Types.
|
14
|
+
modules = Scale::Types.get("Vec<MetadataV8Module>").decode(scale_bytes).value
|
15
15
|
|
16
16
|
value = {
|
17
17
|
magicNumber: 1_635_018_093,
|
@@ -49,7 +49,7 @@ module Scale
|
|
49
49
|
end
|
50
50
|
|
51
51
|
class MetadataV8Module
|
52
|
-
include
|
52
|
+
include Base
|
53
53
|
def self.decode(scale_bytes)
|
54
54
|
name = String.decode(scale_bytes).value
|
55
55
|
|
@@ -66,29 +66,29 @@ module Scale
|
|
66
66
|
|
67
67
|
has_calls = Bool.decode(scale_bytes).value
|
68
68
|
if has_calls
|
69
|
-
calls = Scale::Types.
|
69
|
+
calls = Scale::Types.get("Vec<MetadataModuleCall>").decode(scale_bytes).value
|
70
70
|
result[:calls] = calls.map(&:value)
|
71
71
|
end
|
72
72
|
|
73
73
|
has_events = Bool.decode(scale_bytes).value
|
74
74
|
if has_events
|
75
|
-
events = Scale::Types.
|
75
|
+
events = Scale::Types.get("Vec<MetadataModuleEvent>").decode(scale_bytes).value
|
76
76
|
result[:events] = events.map(&:value)
|
77
77
|
end
|
78
78
|
|
79
|
-
result[:constants] = Scale::Types.
|
80
|
-
result[:errors] = Scale::Types.
|
79
|
+
result[:constants] = Scale::Types.get("Vec<MetadataV7ModuleConstants>").decode(scale_bytes).value.map(&:value)
|
80
|
+
result[:errors] = Scale::Types.get("Vec<MetadataModuleError>").decode(scale_bytes).value.map(&:value)
|
81
81
|
|
82
82
|
MetadataV8Module.new(result)
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
86
|
class MetadataModuleError
|
87
|
-
include
|
87
|
+
include Base
|
88
88
|
def self.decode(scale_bytes)
|
89
89
|
result = {
|
90
90
|
name: String.decode(scale_bytes).value,
|
91
|
-
documentation: Scale::Types.
|
91
|
+
documentation: Scale::Types.get("Vec<String>").decode(scale_bytes).value.map(&:value)
|
92
92
|
}
|
93
93
|
|
94
94
|
MetadataModuleError.new(result)
|
data/lib/metadata/metadata_v9.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Scale
|
2
2
|
module Types
|
3
3
|
class MetadataV9
|
4
|
-
include
|
4
|
+
include Base
|
5
5
|
attr_accessor :call_index, :event_index
|
6
6
|
|
7
7
|
def initialize(value)
|
@@ -11,7 +11,7 @@ module Scale
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.decode(scale_bytes)
|
14
|
-
modules = Scale::Types.
|
14
|
+
modules = Scale::Types.get("Vec<MetadataV8Module>").decode(scale_bytes).value
|
15
15
|
|
16
16
|
value = {
|
17
17
|
magicNumber: 1_635_018_093,
|
data/lib/scale.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
require "scale/version"
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "common"
|
4
|
+
|
4
5
|
require "json"
|
5
6
|
require "singleton"
|
6
7
|
|
8
|
+
require "scale_bytes"
|
9
|
+
|
10
|
+
require "type_registry"
|
11
|
+
require "type_builder"
|
12
|
+
|
7
13
|
require "scale/base"
|
8
14
|
require "scale/types"
|
9
15
|
require "scale/block"
|
@@ -23,362 +29,36 @@ require "metadata/metadata_v9"
|
|
23
29
|
require "metadata/metadata_v10"
|
24
30
|
require "metadata/metadata_v11"
|
25
31
|
require "metadata/metadata_v12"
|
32
|
+
require "metadata/metadata_v13"
|
26
33
|
|
27
34
|
require "substrate_client"
|
28
35
|
require "logger"
|
29
36
|
require "helper"
|
30
|
-
require 'kontena-websocket-client'
|
31
|
-
|
32
|
-
class String
|
33
|
-
def upcase_first
|
34
|
-
self.sub(/\S/, &:upcase)
|
35
|
-
end
|
36
|
-
|
37
|
-
def camelize
|
38
|
-
self.split('_').collect(&:upcase_first).join
|
39
|
-
end
|
40
|
-
|
41
|
-
def underscore
|
42
|
-
self.gsub(/::/, '/').
|
43
|
-
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
44
|
-
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
45
|
-
tr("-", "_").
|
46
|
-
downcase
|
47
|
-
end
|
48
|
-
end
|
49
37
|
|
50
38
|
module Scale
|
51
|
-
class
|
52
|
-
|
53
|
-
class
|
54
|
-
|
39
|
+
class ScaleError < StandardError; end
|
40
|
+
class TypeBuildError < ScaleError; end
|
41
|
+
class BadDataError < ScaleError; end
|
42
|
+
class TypeRegistryNotLoadYet < ScaleError; end
|
43
|
+
class StorageInputTypeError < ScaleError; end
|
55
44
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
# will change by different spec version
|
61
|
-
attr_accessor :spec_version # optional
|
62
|
-
attr_accessor :metadata
|
63
|
-
|
64
|
-
def load(spec_name: nil, custom_types: nil)
|
65
|
-
@spec_name = nil
|
66
|
-
@types = nil
|
67
|
-
@versioning = nil
|
68
|
-
@custom_types = nil
|
69
|
-
|
70
|
-
default_types, _, _ = load_chain_spec_types("default")
|
45
|
+
module Types
|
46
|
+
class << self
|
47
|
+
attr_accessor :debug
|
48
|
+
end
|
71
49
|
|
72
|
-
|
50
|
+
def self.check_types
|
51
|
+
TypeRegistry.instance.all_types.keys.each do |key|
|
73
52
|
begin
|
74
|
-
|
75
|
-
spec_types, @versioning, @spec_version = load_chain_spec_types(spec_name)
|
76
|
-
@types = default_types.merge(spec_types)
|
53
|
+
type = self.get(key)
|
77
54
|
rescue => ex
|
78
|
-
puts "
|
79
|
-
@types = default_types
|
55
|
+
puts "[[ERROR]] #{key}: #{ex}"
|
80
56
|
end
|
81
|
-
else
|
82
|
-
@spec_name = "default"
|
83
|
-
@types = default_types
|
84
57
|
end
|
85
|
-
|
86
|
-
self.custom_types = custom_types
|
87
58
|
true
|
88
59
|
end
|
89
60
|
|
90
|
-
def get(type_name)
|
91
|
-
raise "Types not loaded" if @types.nil?
|
92
|
-
|
93
|
-
all_types = {}.merge(@types)
|
94
|
-
|
95
|
-
if @spec_version && @versioning
|
96
|
-
@versioning.each do |item|
|
97
|
-
if @spec_version >= item["runtime_range"][0] &&
|
98
|
-
( item["runtime_range"][1].nil? || @spec_version <= item["runtime_range"][1] )
|
99
|
-
all_types.merge!(item["types"])
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
all_types.merge!(@custom_types) if @custom_types
|
105
|
-
|
106
|
-
type = type_traverse(type_name, all_types)
|
107
|
-
|
108
|
-
Scale::Types.constantize(type)
|
109
|
-
end
|
110
|
-
|
111
|
-
def custom_types=(custom_types)
|
112
|
-
@custom_types = custom_types.stringify_keys if (not custom_types.nil?) && custom_types.class.name == "Hash"
|
113
|
-
end
|
114
|
-
|
115
|
-
private
|
116
|
-
|
117
|
-
def load_chain_spec_types(spec_name)
|
118
|
-
file = File.join File.expand_path("../..", __FILE__), "lib", "type_registry", "#{spec_name}.json"
|
119
|
-
json_string = File.open(file).read
|
120
|
-
json = JSON.parse(json_string)
|
121
|
-
|
122
|
-
runtime_id = json["runtime_id"]
|
123
|
-
|
124
|
-
[json["types"], json["versioning"], runtime_id]
|
125
|
-
end
|
126
|
-
|
127
|
-
def type_traverse(type, types)
|
128
|
-
type = rename(type) if type.class == ::String
|
129
|
-
if types.has_key?(type) && types[type] != type
|
130
|
-
type_traverse(types[type], types)
|
131
|
-
else
|
132
|
-
type
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
# TODO: == implement
|
138
|
-
|
139
|
-
class Bytes
|
140
|
-
attr_reader :data, :bytes
|
141
|
-
attr_reader :offset
|
142
|
-
|
143
|
-
def initialize(data)
|
144
|
-
if (data.class == Array) && data.is_byte_array?
|
145
|
-
@bytes = data
|
146
|
-
elsif (data.class == String) && data.start_with?("0x") && (data.length % 2 == 0)
|
147
|
-
arr = data[2..].scan(/../).map(&:hex)
|
148
|
-
@bytes = arr
|
149
|
-
else
|
150
|
-
raise "Provided data is not valid"
|
151
|
-
end
|
152
|
-
|
153
|
-
@data = data
|
154
|
-
@offset = 0
|
155
|
-
end
|
156
|
-
|
157
|
-
def reset_offset
|
158
|
-
@offset = 0
|
159
|
-
end
|
160
|
-
|
161
|
-
def get_next_bytes(length)
|
162
|
-
result = @bytes[@offset...@offset + length]
|
163
|
-
if result.length < length
|
164
|
-
str = @data[(2 + @offset * 2)..]
|
165
|
-
str = str.length > 40 ? (str[0...40]).to_s + "..." : str
|
166
|
-
raise "No enough data: #{str}, expect length: #{length}, but #{result.length}"
|
167
|
-
end
|
168
|
-
@offset += length
|
169
|
-
result
|
170
|
-
rescue RangeError => ex
|
171
|
-
puts "length: #{length}"
|
172
|
-
puts ex.message
|
173
|
-
puts ex.backtrace
|
174
|
-
end
|
175
|
-
|
176
|
-
def get_remaining_bytes
|
177
|
-
@bytes[offset..]
|
178
|
-
end
|
179
|
-
|
180
|
-
def to_hex_string
|
181
|
-
@bytes.bytes_to_hex
|
182
|
-
end
|
183
|
-
|
184
|
-
def to_bin_string
|
185
|
-
@bytes.bytes_to_bin
|
186
|
-
end
|
187
|
-
|
188
|
-
def to_ascii
|
189
|
-
@bytes[0...offset].pack("C*") + "<================================>" + @bytes[offset..].pack("C*")
|
190
|
-
end
|
191
|
-
|
192
|
-
def ==(other)
|
193
|
-
bytes == other.bytes && offset == other.offset
|
194
|
-
end
|
195
|
-
|
196
|
-
def to_s
|
197
|
-
green(@bytes[0...offset].bytes_to_hex) + yellow(@bytes[offset..].bytes_to_hex[2..])
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
class TypesLoader
|
202
|
-
def self.load(filename)
|
203
|
-
path = File.join File.dirname(__FILE__), "types", filename
|
204
|
-
content = File.open(path).read
|
205
|
-
result = JSON.parse content
|
206
|
-
|
207
|
-
types = result["default"]
|
208
|
-
types.each do |name, body|
|
209
|
-
if body.class == String
|
210
|
-
target_type = "Scale::Types::#{body}"
|
211
|
-
klass = Class.new(target_type.constantize) do
|
212
|
-
end
|
213
|
-
elsif body.class == Hash
|
214
|
-
if body["type"] == "struct"
|
215
|
-
struct_params = {}
|
216
|
-
body["type_mapping"].each do |mapping|
|
217
|
-
struct_params[mapping[0].to_sym] = mapping[1]
|
218
|
-
end
|
219
|
-
klass = Class.new do
|
220
|
-
end
|
221
|
-
klass.send(:include, Scale::Types::Struct)
|
222
|
-
klass.send(:items, struct_params)
|
223
|
-
Scale::Types.const_set name, klass
|
224
|
-
elsif body["type"] = "enum"
|
225
|
-
klass = Class.new do
|
226
|
-
end
|
227
|
-
klass.send(:include, Scale::Types::Enum)
|
228
|
-
if body["type_mapping"]
|
229
|
-
struct_params = {}
|
230
|
-
body["type_mapping"].each do |mapping|
|
231
|
-
struct_params[mapping[0].to_sym] = mapping[1]
|
232
|
-
end
|
233
|
-
klass.send(:items, struct_params)
|
234
|
-
else
|
235
|
-
klass.send(:values, body["value_list"])
|
236
|
-
end
|
237
|
-
Scale::Types.const_set name, klass
|
238
|
-
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
end
|
242
61
|
end
|
243
|
-
|
244
|
-
module Types
|
245
|
-
def self.list
|
246
|
-
TypeRegistry.instance.types
|
247
|
-
end
|
248
|
-
|
249
|
-
def self.get(type_name)
|
250
|
-
TypeRegistry.instance.get(type_name)
|
251
|
-
end
|
252
|
-
|
253
|
-
def self.constantize(type)
|
254
|
-
if type.class == ::String
|
255
|
-
type_of(type.strip)
|
256
|
-
else
|
257
|
-
if type["type"] == "enum" && type.has_key?("type_mapping")
|
258
|
-
type_of("Enum", type["type_mapping"].to_h)
|
259
|
-
elsif type["type"] == "enum" && type.has_key?("value_list")
|
260
|
-
type_of("Enum", type["value_list"])
|
261
|
-
elsif type["type"] == "struct"
|
262
|
-
type_of("Struct", type["type_mapping"].to_h)
|
263
|
-
elsif type["type"] == "set"
|
264
|
-
type_of("Set", type["value_list"])
|
265
|
-
end
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
def self.type_of(type_string, values = nil)
|
270
|
-
if type_string.end_with?(">")
|
271
|
-
type_strs = type_string.scan(/^([^<]*)<(.+)>$/).first
|
272
|
-
type_str = type_strs.first
|
273
|
-
inner_type_str = type_strs.last
|
274
|
-
|
275
|
-
if type_str == "Vec" || type_str == "Option"
|
276
|
-
klass = Class.new do
|
277
|
-
include Scale::Types.type_of(type_str)
|
278
|
-
inner_type inner_type_str
|
279
|
-
end
|
280
|
-
name = "#{type_str}<#{inner_type_str.camelize}>_#{klass.object_id}"
|
281
|
-
Scale::Types.const_set fix(name), klass
|
282
|
-
else
|
283
|
-
raise "#{type_str} not support inner type: #{type_string}"
|
284
|
-
end
|
285
|
-
elsif type_string.start_with?("(") && type_string.end_with?(")") # tuple
|
286
|
-
# TODO: add nested tuple support
|
287
|
-
types_with_inner_type = type_string[1...-1].scan(/([A-Za-z]+<[^>]*>)/).first
|
288
|
-
|
289
|
-
types_with_inner_type&.each do |type_str|
|
290
|
-
new_type_str = type_str.tr(",", ";")
|
291
|
-
type_string = type_string.gsub(type_str, new_type_str)
|
292
|
-
end
|
293
|
-
|
294
|
-
type_strs = type_string[1...-1].split(",").map do |type_str|
|
295
|
-
type_str.strip.tr(";", ",")
|
296
|
-
end
|
297
|
-
|
298
|
-
klass = Class.new do
|
299
|
-
include Scale::Types::Tuple
|
300
|
-
inner_types *type_strs
|
301
|
-
end
|
302
|
-
name = "Tuple_Of_#{type_strs.map(&:camelize).join("_")}_#{klass.object_id}"
|
303
|
-
Scale::Types.const_set fix(name), klass
|
304
|
-
else
|
305
|
-
if type_string == "Enum"
|
306
|
-
# TODO: combine values to items
|
307
|
-
klass = Class.new do
|
308
|
-
include Scale::Types::Enum
|
309
|
-
if values.class == ::Hash
|
310
|
-
items values
|
311
|
-
else
|
312
|
-
values(*values)
|
313
|
-
end
|
314
|
-
end
|
315
|
-
name = values.class == ::Hash ? values.values.map(&:camelize).join("_") : values.map(&:camelize).join("_")
|
316
|
-
name = "Enum_Of_#{name}_#{klass.object_id}"
|
317
|
-
Scale::Types.const_set fix(name), klass
|
318
|
-
elsif type_string == "Struct"
|
319
|
-
klass = Class.new do
|
320
|
-
include Scale::Types::Struct
|
321
|
-
items values
|
322
|
-
end
|
323
|
-
name = "Struct_Of_#{values.values.map(&:camelize).join("_")}_#{klass.object_id}"
|
324
|
-
Scale::Types.const_set fix(name), klass
|
325
|
-
elsif type_string == "Set"
|
326
|
-
klass = Class.new do
|
327
|
-
include Scale::Types::Set
|
328
|
-
items values, 1
|
329
|
-
end
|
330
|
-
name = "Set_Of_#{values.keys.map(&:camelize).join("_")}_#{klass.object_id}"
|
331
|
-
Scale::Types.const_set fix(name), klass
|
332
|
-
else
|
333
|
-
type_name = (type_string.start_with?("Scale::Types::") ? type_string : "Scale::Types::#{type_string}")
|
334
|
-
begin
|
335
|
-
type_name.constantize
|
336
|
-
rescue NameError => e
|
337
|
-
puts "#{type_string} is not defined"
|
338
|
-
end
|
339
|
-
end
|
340
|
-
end
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
end
|
345
|
-
|
346
|
-
def fix(name)
|
347
|
-
name
|
348
|
-
.gsub("<", "˂").gsub(">", "˃")
|
349
|
-
.gsub("(", "⁽").gsub(")", "⁾")
|
350
|
-
.gsub(" ", "").gsub(",", "‚")
|
351
|
-
.gsub(":", "։")
|
352
|
-
end
|
353
|
-
|
354
|
-
def rename(type)
|
355
|
-
type = type.gsub("T::", "")
|
356
|
-
.gsub("<T>", "")
|
357
|
-
.gsub("<T as Trait>::", "")
|
358
|
-
.delete("\n")
|
359
|
-
.gsub("EventRecord<Event, Hash>", "EventRecord")
|
360
|
-
.gsub(/(u)(\d+)/, 'U\2')
|
361
|
-
return "Bool" if type == "bool"
|
362
|
-
return "Null" if type == "()"
|
363
|
-
return "String" if type == "Vec<u8>"
|
364
|
-
return "Compact" if type == "Compact<u32>" || type == "Compact<U32>"
|
365
|
-
return "Address" if type == "<Lookup as StaticLookup>::Source"
|
366
|
-
return "Vec<Address>" if type == "Vec<<Lookup as StaticLookup>::Source>"
|
367
|
-
return "Compact" if type == "<Balance as HasCompact>::Type"
|
368
|
-
return "Compact" if type == "<BlockNumber as HasCompact>::Type"
|
369
|
-
return "Compact" if type == "Compact<Balance>"
|
370
|
-
return "Compact" if type == "Compact<BlockNumber>"
|
371
|
-
return "CompactMoment" if type == "<Moment as HasCompact>::Type"
|
372
|
-
return "CompactMoment" if type == "Compact<Moment>"
|
373
|
-
return "InherentOfflineReport" if type == "<InherentOfflineReport as InherentOfflineReport>::Inherent"
|
374
|
-
return "AccountData" if type == "AccountData<Balance>"
|
375
|
-
|
376
|
-
if type =~ /\[U\d+; \d+\]/
|
377
|
-
byte_length = type.scan(/\[U\d+; (\d+)\]/).first.first.to_i
|
378
|
-
return "VecU8Length#{byte_length}"
|
379
|
-
end
|
380
|
-
|
381
|
-
type
|
382
62
|
end
|
383
63
|
|
384
64
|
def green(text)
|
@@ -389,6 +69,24 @@ def yellow(text)
|
|
389
69
|
"\033[33m#{text}\033[0m"
|
390
70
|
end
|
391
71
|
|
72
|
+
class String
|
73
|
+
def upcase_first
|
74
|
+
self.sub(/\S/, &:upcase)
|
75
|
+
end
|
76
|
+
|
77
|
+
def camelize2
|
78
|
+
self.split('_').collect(&:upcase_first).join
|
79
|
+
end
|
80
|
+
|
81
|
+
def underscore2
|
82
|
+
self.gsub(/::/, '/').
|
83
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
84
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
85
|
+
tr("-", "_").
|
86
|
+
downcase
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
392
90
|
# https://www.ruby-forum.com/t/question-about-hex-signed-int/125510/4
|
393
91
|
# machine bit length:
|
394
92
|
# machine_byte_length = ['foo'].pack('p').size
|
@@ -426,3 +124,5 @@ class ::Hash
|
|
426
124
|
Hash[h]
|
427
125
|
end
|
428
126
|
end
|
127
|
+
|
128
|
+
Scale::Types.debug = false
|