bit-protocol 1.0.1
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 +7 -0
- data/GEMFILE +2 -0
- data/LICENSE +9 -0
- data/README.md +112 -0
- data/bitop.rb +57 -0
- data/bitproto.rb +174 -0
- data/bitstream.rb +29 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d3b4bed5a4a0d7557fc41fa9c9a99483284b1d98f4837de98530982fedbbbd71
|
4
|
+
data.tar.gz: 9dae1cf57c7cc9cfb90d0d79f80fdbf2196199b8e2087c61295cd1c410132acd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d6c8abc14a7ee4c3f61def944e08dbbf75a3930f41e7d78820a0a086a3504c46040b91079fddc7e9edbae4aafcbeed316fbb68cb968dc96cc9fe0b033e3bc1e6
|
7
|
+
data.tar.gz: e4b7f2570af27f2161329bb34b7d708a5c7b2d67e93bfd87112f2f8e0fc40a157ef8982539b20627dbfcdd00f5c400823f2173684729cc820c583295bc75597c
|
data/GEMFILE
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 ChenMeng1365
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# bitproto
|
2
|
+
|
3
|
+
主要用于位操作、位解构和二进制编码。
|
4
|
+
|
5
|
+
## BitOp
|
6
|
+
|
7
|
+
位操作模块,提供基本二进制比特位的操作。
|
8
|
+
|
9
|
+
分组 & 截取:
|
10
|
+
|
11
|
+
- `stack(num)`将整数按8位分组。
|
12
|
+
- `hextack(num)`将整数按4位分组。
|
13
|
+
- `seek(bitstream, hidx, tidx, full)`截取比特位串`bitstream`的子串(从`hidx`到`tidx`),`full`设置为字符串省略长度,对超长字符串仅显示部分子串(不影响其值)。
|
14
|
+
|
15
|
+
进制转换 & 值面转换:
|
16
|
+
|
17
|
+
- `hex2bin(num)`对于(十六进制)大整数,按8位二进制分组转换为字符串并连接起来;对于十六进制字符串,按4位二进制分组转换为字符串并连接起来。
|
18
|
+
- `bin2hex(num)`对于(二进制)大整数,按1位十六进制分组转换为字符串并连接起来;对于二进制字符串,按1位十六进制分组转换为字符串并连接起来。
|
19
|
+
- `bitval(num)`将二进制字符串转换为整数。
|
20
|
+
- `hexval(num)`将十六进制字符串转换为整数。
|
21
|
+
|
22
|
+
## BitStream
|
23
|
+
|
24
|
+
定义了比特位数据流字符串,以整数序列按字节存储。
|
25
|
+
|
26
|
+
导入方式 & 值展示方式:
|
27
|
+
|
28
|
+
- 表值的数字字符串(`:hex`,`:bin`,`:dec`)
|
29
|
+
- 原始二进制数据(`:raw`)
|
30
|
+
- 整数序列(`:seq`)
|
31
|
+
|
32
|
+
## BitMark
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
## BitProtocol
|
37
|
+
|
38
|
+
定义了以比特位组织数据的协议,用于对比特位数据流进行解析和编码。
|
39
|
+
|
40
|
+
※ 临时实现,建议重写 ※
|
41
|
+
|
42
|
+
协议载入方法:
|
43
|
+
|
44
|
+
- load(path): 读取指定协议(JSON)文件
|
45
|
+
- parse(setting,reset_flag): 解析协议(JSON)文档
|
46
|
+
- reset(): 重置协议生成树
|
47
|
+
|
48
|
+
表达式解析方法:
|
49
|
+
|
50
|
+
- eval(type, content): 根据类型估值
|
51
|
+
- expr(condition): 条件表达式拆分,解析为变量、操作符、值序列
|
52
|
+
- var(condition): 条件表达式解析,以`${}`或`$[]`提取变量中的名称
|
53
|
+
- words(condition): 条件表达式解析,以`()`提取序列,以`,`分隔子元素
|
54
|
+
- oprt(condition): 条件表达式解析,提取`==`、`in`、`exist`等操作符
|
55
|
+
|
56
|
+
查询实现方法:
|
57
|
+
|
58
|
+
- trace(tree,rtree,dom): 字段验证中**查询**的一种实现方法,通过遍历字段值树,构成一组带有实例值的反向查询路径
|
59
|
+
- rtrace(tree,key,dom): 字段验证中**查询**的一种实现方法,根据反向查询路径构成一颗反向查询树
|
60
|
+
|
61
|
+
估值验证方法:
|
62
|
+
|
63
|
+
- validate(env): 根据环境变量验证协议生成树,根据验证的当前方式,需要做两次估值检查
|
64
|
+
- evaluate(expr): 条件表达式估值,给协议生成树变量赋值
|
65
|
+
- verify(verification, should, actual, &process): 根据验证原则和验证方式,判断协议预定值和数据流实际值是否符合
|
66
|
+
- finale(criteria, result): 根据验证结果和验证准则设置,判断是否通过验证
|
67
|
+
- normal?(report, rule): 输入规则决定协议匹配后是否达成某项协议的正常结果
|
68
|
+
|
69
|
+
该模块维持两个存储:`@_bp_`(比特协议数据流)和`@_pt_`(协议生成树)。前者用以将比特位协议文档读取,加载为原生数据;后者负责构建协议树结构,并验证一些检查条件。
|
70
|
+
|
71
|
+
比特位协议通过字段定义数据结构和所需维持的规范。
|
72
|
+
|
73
|
+
一个转换为JSON格式的原始比特协议数据流字段如下:
|
74
|
+
|
75
|
+
```json
|
76
|
+
"字段名称": {
|
77
|
+
"description": "字段描述",
|
78
|
+
"start-bit": 0, // 字段起始位索引
|
79
|
+
"finish-bit": 19, // 字段结束位索引
|
80
|
+
"type": "HEX", // 字段类型
|
81
|
+
"value": { // 字段值
|
82
|
+
"字段值": "字段值描述"
|
83
|
+
},
|
84
|
+
"condition": "字段存在条件", // 字段存在条件
|
85
|
+
"verification": "精确匹配", // 字段验证方式
|
86
|
+
"criteria": "失败" // 字段验证结果
|
87
|
+
},
|
88
|
+
```
|
89
|
+
|
90
|
+
* 字段名称、字段描述、字段值描述:均为字符串,用以帮助理解该字段含义。
|
91
|
+
* 字段起始位索引、字段结束位索引:为非负正整数,指定比特位范围,计数从0开始。
|
92
|
+
* 字段类型:字符串,指定字段值的值表示方式。这里的表示方式,是指对数据流解构后,按协议中本处指定的方式进行数据处理,得到的数据值。比如指名为`HEX`,表示获取该字段数据后,以十六进制字符串形式转换数据,再对其进行校验和运算。`HEX`、`BIN`、`DEC`均是字符串,`STR`为无限制字符串,`INT`和`FLT`为整数和浮点数,`PTR`为仅作提取不做展示加工的原始数据,一般用于运算。可以在类型后面标注长度以方便对齐,比如`BIN(4)`、`HEX(2)`等。
|
93
|
+
* 字段值:散列对象,键值对表示字段值和其描述。字段值的设定需要和字段类型保持一致,一般一个具体的字段值是枚举值类型的实例,但为了提高匹配效率,也可以通过列表(`Array`)、范围(`Range`)、集合(`Set`)等方式为一类值做归集。还`PTR`类型是个例外,它的值是协议中另外一个字段名称。
|
94
|
+
* 字段值验证方式:字符串,指定字段值的验证方式,根据值的指定方式支持逻辑运算、比较运算、集合运算、谓词运算和查询操作,具体谓词见<< Verification >>。其中除了查询是根据值反向查询描述来匹配其含义,其他验证方式均直接对值进行运算并校验。
|
95
|
+
* 字段存在条件:字符串,有些场合字段并非必须出现,通过校验该字段是否存在的条件表达式,在估值不成立时不适用该字段。表达式中适用各类运算符甚至函数,使用`$[PTR]`来指向另一个字段并引用其值。
|
96
|
+
* 字段值验证结果:字符串,指定字段验证结果的作用,当验证`失败`时,该字段不通过,数据流不匹配协议;当验证`忽略`时,即使字段验证失败,也不影响数据流适用其他的匹配。
|
97
|
+
|
98
|
+
| Verification | Name | Description |
|
99
|
+
| ------------ | ---- | ----------- |
|
100
|
+
| AND | 且 | 逻辑 |
|
101
|
+
| OR | 或 | 逻辑 |
|
102
|
+
| NOT | 非 | 逻辑 |
|
103
|
+
| MATCH | 匹配 | 精确 |
|
104
|
+
| LESS | 小于 | 精确 |
|
105
|
+
| GREATER | 大于 | 精确 |
|
106
|
+
| IN | 属于 | 范围 |
|
107
|
+
| INCLUDE | 包含 | 范围 |
|
108
|
+
| EXIST | 存在 | 限定 |
|
109
|
+
| ALL | 全部 | 限定 |
|
110
|
+
| QUERY | 查询 | 反向 |
|
111
|
+
|
112
|
+
<< Verification >>
|
data/bitop.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
module BitOp
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def stack num
|
6
|
+
sequence, left = [], num
|
7
|
+
until left==0
|
8
|
+
rest = left & 0b11111111
|
9
|
+
left = left >> 8
|
10
|
+
sequence.unshift rest
|
11
|
+
end
|
12
|
+
return sequence
|
13
|
+
end
|
14
|
+
|
15
|
+
def hextack num
|
16
|
+
sequence, left = [], num
|
17
|
+
until left==0
|
18
|
+
rest = left & 0b1111
|
19
|
+
left = left >> 4
|
20
|
+
sequence.unshift rest
|
21
|
+
end
|
22
|
+
return sequence
|
23
|
+
end
|
24
|
+
|
25
|
+
def hex2bin num
|
26
|
+
return self.stack(num).map{|c|"%08b"%c}.join if num.is_a?(Integer)
|
27
|
+
return num.each_char.map{|c|"%04b" % (eval("0x#{c}"))}.join if num.is_a?(String)
|
28
|
+
end
|
29
|
+
|
30
|
+
def bitval num
|
31
|
+
eval("0b"+num)
|
32
|
+
end
|
33
|
+
|
34
|
+
def bin2hex num
|
35
|
+
return self.hextack(num).map{|c|"%0x"%c}.join if num.is_a?(Integer)
|
36
|
+
return num.split('').each_slice(4).map{|c|"%0x"%eval("0b#{c.join}")}.join if num.is_a?(String)
|
37
|
+
end
|
38
|
+
|
39
|
+
def hexval num
|
40
|
+
eval("0x"+num)
|
41
|
+
end
|
42
|
+
|
43
|
+
def seek bitstream, head_index=nil, tail_index=nil, full=false
|
44
|
+
q = bitstream.val(:seq, full).select{|c|c!='...'}.map{|c|"%08b"%c}.join
|
45
|
+
s = 0 if head_index==:first || head_index==nil
|
46
|
+
s = q.length + head_index if head_index.is_a?(Integer) && head_index < 0
|
47
|
+
s = head_index if head_index.is_a?(Integer) && head_index >= 0
|
48
|
+
s = q.length - 1 if head_index.is_a?(Integer) && head_index >= q.length
|
49
|
+
e = -1 if tail_index==:last
|
50
|
+
e = q.length + tail_index if tail_index.is_a?(Integer) && tail_index < 0
|
51
|
+
e = tail_index if tail_index.is_a?(Integer) && tail_index >= 0
|
52
|
+
e = q.length - 1 if tail_index.is_a?(Integer) && tail_index >= q.length
|
53
|
+
e = s if tail_index==nil || (e.is_a?(Integer) && s.is_a?(Integer) && e < s)
|
54
|
+
# p [q, s, e]
|
55
|
+
q[s..e]
|
56
|
+
end
|
57
|
+
end
|
data/bitproto.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'bitop'
|
2
|
+
require 'bitstream'
|
3
|
+
|
4
|
+
module BitProtocol
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def load path
|
8
|
+
self.reset unless @_pt_
|
9
|
+
path = path[-5..-1]=='.json' ? path : path+'.json'
|
10
|
+
@_bp_ = JSON.parse File.read(path)
|
11
|
+
return @_bp_, @_pt_
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse setting, reset=false
|
15
|
+
self.reset if !@_pt_ || reset
|
16
|
+
@_bp_ = JSON.parse setting
|
17
|
+
return @_bp_, @_pt_
|
18
|
+
end
|
19
|
+
|
20
|
+
def reset
|
21
|
+
@_pt_ = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate env={}
|
25
|
+
inst, checks,report = env[:instance], [], []
|
26
|
+
(puts "Instance of BitProtocol is nil.";return nil) unless inst
|
27
|
+
console_log = env[:log]
|
28
|
+
|
29
|
+
@_bp_.each do|key, set|
|
30
|
+
desc = set['description']
|
31
|
+
si, ei = set['start-bit'], set['finish-bit']
|
32
|
+
type = set['type']
|
33
|
+
should = set['value']
|
34
|
+
|
35
|
+
bits = BitOp.seek(inst, si, ei)
|
36
|
+
actual = self.eval(type, bits)
|
37
|
+
|
38
|
+
cond = set['condition'] ? self.expr(set['condition']) : []
|
39
|
+
vrfy = verify(set['verification'], should, actual)
|
40
|
+
cert = finale(set['criteria'], vrfy)
|
41
|
+
|
42
|
+
@_pt_["$[#{key}]"] = actual if self.evaluate(cond) && vrfy
|
43
|
+
checks << [key, desc, si, ei, type, should, actual, cond, vrfy, cert]
|
44
|
+
end
|
45
|
+
|
46
|
+
checkz = []
|
47
|
+
checks.each do|check|
|
48
|
+
key, desc, si, ei, type, should, actual, cond, vrfy, cert = check
|
49
|
+
if vrfy && self.evaluate(cond)
|
50
|
+
@_pt_["$[#{key}]"] = actual
|
51
|
+
end
|
52
|
+
checkz << [key, desc, si, ei, type, should, actual, cond, vrfy, cert]
|
53
|
+
end
|
54
|
+
|
55
|
+
checkz.each do|check|
|
56
|
+
key, desc, si, ei, type, should, actual, cond, vrfy, cert = check
|
57
|
+
|
58
|
+
if self.finale(cert, vrfy) && self.evaluate(cond)
|
59
|
+
puts "Field #{key} is #{desc}." if console_log
|
60
|
+
show = (vrfy && should[actual]) ? should[actual] : (vrfy && vrfy!=true) ? vrfy : ''
|
61
|
+
puts "From #{si} to #{ei} is #{actual}, check should be #{!vrfy ? false : true}. >>>> #{show}" if console_log
|
62
|
+
unless cond.empty?
|
63
|
+
evar = self.evaluate(cond)
|
64
|
+
puts "Condition Expression is #{cond}, evaluation is #{evar}." if console_log
|
65
|
+
end
|
66
|
+
puts Array.new(128){'='}.join if console_log if console_log
|
67
|
+
|
68
|
+
report << [key.gsub('$[','').gsub(']',''), desc, show, actual, "#{type}[#{si}-#{ei}]"]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
return report, @_pt_
|
73
|
+
end
|
74
|
+
|
75
|
+
def eval type, content
|
76
|
+
return case type
|
77
|
+
when 'HEX'; BitOp.bin2hex(content).to_s.upcase
|
78
|
+
when 'BIN'; content
|
79
|
+
when 'BIN(4)'; Array.new(4-content.length){'0'}.join+content
|
80
|
+
# when 'DEC';
|
81
|
+
when 'STR'; content
|
82
|
+
else; nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def expr condition
|
87
|
+
vars = self.var(condition)
|
88
|
+
opts = self.oprt(condition)
|
89
|
+
words = self.words(condition)
|
90
|
+
vars = words.include?(vars) ? vars : vars
|
91
|
+
vals = words.include?(opts) ? words[(words.index(opts)+1)..-1] : words
|
92
|
+
return [vars, opts, vals]
|
93
|
+
end
|
94
|
+
|
95
|
+
def var condition
|
96
|
+
field = condition.to_s.match(/\$(\[|\{){1}(\w[\d|\_|\w]+)+(\]|\}){1}/).to_s
|
97
|
+
name = field.empty? ? nil : field.split('{').last.split('}').first
|
98
|
+
return name
|
99
|
+
end
|
100
|
+
|
101
|
+
def words condition
|
102
|
+
value = condition.to_s.match(/(\(){0,1}.*[\,|.]+.*(\)){0,1}/).to_s
|
103
|
+
list = (value.empty? ? condition.split(' ') : value.split('(').last.split(')').first.to_s.split(',')).map{|s|s.strip}
|
104
|
+
return list
|
105
|
+
end
|
106
|
+
|
107
|
+
def oprt condition
|
108
|
+
return '==' if condition.to_s.include? '=='
|
109
|
+
return 'in' if condition.to_s.include? 'in'
|
110
|
+
return 'exist' if condition.to_s.include? 'exist'
|
111
|
+
return nil
|
112
|
+
end
|
113
|
+
|
114
|
+
def evaluate expr
|
115
|
+
vars, opts, vals = expr # vars include $[] here
|
116
|
+
# p [vars, @_pt_[vars], opts, vals]
|
117
|
+
return case opts
|
118
|
+
when '=='; @_pt_[vars] == vals.first
|
119
|
+
when 'in'; vals.include?(@_pt_[vars])
|
120
|
+
when 'exist'; !!@_pt_[vars]
|
121
|
+
else; true
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def verify verification, should, actual, &process
|
126
|
+
return case verification
|
127
|
+
when '精确匹配'
|
128
|
+
should.keys.include? actual
|
129
|
+
when '精确查询'
|
130
|
+
locate = self.rtrace(should, actual, '')
|
131
|
+
locate ? locate.gsub('/',' ').strip : false
|
132
|
+
else
|
133
|
+
false
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def finale criteria, result
|
138
|
+
return case criteria
|
139
|
+
when '失败'; result
|
140
|
+
when '忽略'; !result
|
141
|
+
else; result; end
|
142
|
+
end
|
143
|
+
|
144
|
+
def trace tree,rtree,dom=''
|
145
|
+
tree.each do|name, node|
|
146
|
+
if node.is_a?(Hash)
|
147
|
+
rtree = self.trace(node, rtree, "#{dom}/#{name}")
|
148
|
+
elsif node.is_a?(Array)
|
149
|
+
node.each do|value| # must be an atom
|
150
|
+
rtree["#{dom}/#{name}"] = value
|
151
|
+
end
|
152
|
+
else
|
153
|
+
rtree["#{dom}/#{name}"] = node
|
154
|
+
end
|
155
|
+
end
|
156
|
+
return rtree
|
157
|
+
end
|
158
|
+
|
159
|
+
def rtrace tree, key, dom=''
|
160
|
+
rsort = self.trace(tree, {}, dom)
|
161
|
+
rtree = {}
|
162
|
+
rsort.each do|path, val|
|
163
|
+
rtree[val]=path
|
164
|
+
end
|
165
|
+
return rtree[key]
|
166
|
+
end
|
167
|
+
|
168
|
+
def normal? report, rule
|
169
|
+
return true if \
|
170
|
+
report.map{|r|r[0]}==['PB','AT','PI1','QoS'] && rule=='一般专线地址' ||
|
171
|
+
report.map{|r|r[0]}==['PB','AT','PI2','CC'] && rule=='网吧专线地址'
|
172
|
+
return false
|
173
|
+
end
|
174
|
+
end
|
data/bitstream.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
class BitStream
|
3
|
+
def initialize option={}
|
4
|
+
option.each do|type, value|
|
5
|
+
case type.to_s.downcase.to_sym
|
6
|
+
when :hex; @stream = BitOp.stack( eval("0x#{value}") )
|
7
|
+
when :bin; @stream = BitOp.stack( eval("0b#{value}") )
|
8
|
+
when :dec; @stream = BitOp.stack( value.to_i )
|
9
|
+
when :raw; @stream = value[0].is_a?(String) ? value.each_byte.map{|c|c.ord} : value
|
10
|
+
when :seq; @stream = value[0].is_a?(Integer) ? value : value.each_char.map{|c|c.ord}
|
11
|
+
else; @stream = []
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def val format='hex', full=false # := number of bytes
|
17
|
+
return [] if full.is_a?(Integer) && full <= 0
|
18
|
+
e = full+1 if full.is_a?(Integer) && full > 0
|
19
|
+
e = 1024 if full==false
|
20
|
+
t = @stream.length >= e ? '...' : nil
|
21
|
+
return case format.to_s.downcase.to_sym
|
22
|
+
when :hex; @stream[0..e].map{|c|"%02x"%c} + (t ? [t] : [])
|
23
|
+
when :bin; @stream[0..e].map{|c|"%08b"%c} + (t ? [t] : [])
|
24
|
+
when :dec; eval("0b"+@stream[0..e].map{|c|"%08b"%c}.join).to_s + (t ? t : '')
|
25
|
+
when :raw; @stream[0..e].map{|c|c.chr}.join + (t ? ' '+t : '')
|
26
|
+
when :seq; @stream[0..e] + (t ? [t] : [])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bit-protocol
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matt
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: cc
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: 1.1.1
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 1.1.1
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: casetdown
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.9.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.9.0
|
40
|
+
description: bit operating, destructuring, and encoding
|
41
|
+
email:
|
42
|
+
- matthrewchains@gmail.com
|
43
|
+
- 18995691365@189.cn
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- GEMFILE
|
49
|
+
- LICENSE
|
50
|
+
- README.md
|
51
|
+
- bitop.rb
|
52
|
+
- bitproto.rb
|
53
|
+
- bitstream.rb
|
54
|
+
homepage: https://github.com/ChenMeng1365/network
|
55
|
+
licenses:
|
56
|
+
- AGPL-3.0
|
57
|
+
metadata: {}
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- "."
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubygems_version: 3.6.9
|
73
|
+
specification_version: 4
|
74
|
+
summary: bitproto
|
75
|
+
test_files: []
|