memory_io 0.2.0 → 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/LICENSE +21 -0
- data/README.md +9 -11
- data/lib/memory_io/io.rb +1 -1
- data/lib/memory_io/process.rb +0 -5
- data/lib/memory_io/types/basic/number.rb +2 -2
- data/lib/memory_io/types/cpp/string.rb +6 -8
- data/lib/memory_io/types/record.rb +4 -4
- data/lib/memory_io/types/type.rb +2 -3
- data/lib/memory_io/types/types.rb +2 -2
- data/lib/memory_io/util.rb +34 -20
- data/lib/memory_io/version.rb +1 -1
- metadata +29 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0f287dc7b3453557bbcda2f2ce09e03d779d0dbff69f8ef059069f03c76da427
|
|
4
|
+
data.tar.gz: a471ab55f6abd70783a220d0939cdd8f84231f59a533a6470a9f64119c184a41
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 959a45d2dcab5ced28be35f6988a6c6fadbd1fd6510e21747727f16e87cabddf23e951ffba71d8deec4baa1be440ce5bd79b1fe54e1bad66a17deb9185c54db9
|
|
7
|
+
data.tar.gz: a1fe1e032d09a53ce4611e2738255ac1444b5a0283e959606a1da232db28c9d0d42a7277977b17d2bb8fcfa476cc58c53368ad64fa970d0b7b91a5536e59e79e
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 david942j
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
[](https://travis-ci.org/david942j/memory_io)
|
|
2
1
|
[](https://badge.fury.io/rb/memory_io)
|
|
3
|
-
[](https://github.com/david942j/memory_io/actions)
|
|
3
|
+
[](https://qlty.sh/gh/david942j/projects/memory_io)
|
|
4
|
+
[](https://qlty.sh/gh/david942j/projects/memory_io)
|
|
5
|
+
[](https://www.rubydoc.info/github/david942j/memory_io/)
|
|
6
6
|
[](http://choosealicense.com/licenses/mit/)
|
|
7
7
|
|
|
8
8
|
# MemoryIO
|
|
@@ -14,8 +14,8 @@ Read/Write complicated structures in memory easily.
|
|
|
14
14
|
I usually need to dump a structure, say `string` in C++, from memory for debugging.
|
|
15
15
|
This is not hard if using gdb.
|
|
16
16
|
However, gdb doesn't support writing Ruby scripts
|
|
17
|
-
(unless you use [gdb-ruby](https://github.com/david942j/gdb-ruby), which has
|
|
18
|
-
So I
|
|
17
|
+
(unless you use [gdb-ruby](https://github.com/david942j/gdb-ruby), which has **MemoryIO** as its dependency).
|
|
18
|
+
So I created this projected to make the debug procedure much easier.
|
|
19
19
|
|
|
20
20
|
This repository has two main goals:
|
|
21
21
|
|
|
@@ -25,16 +25,14 @@ This repository has two main goals:
|
|
|
25
25
|
## Why
|
|
26
26
|
|
|
27
27
|
It's not hard to read/write a process's memory (simply open the file `/proc/$PID/mem`),
|
|
28
|
-
but it still
|
|
28
|
+
but it's still worthy to make a utility.
|
|
29
29
|
|
|
30
|
-
This
|
|
30
|
+
This project also targets to collect all common structures, such as how to parse a C++/Rust/Python object from memory.
|
|
31
31
|
Therefore, **Pull Requests of adding new structures** are welcome :D
|
|
32
32
|
|
|
33
33
|
## Supported Platform
|
|
34
34
|
|
|
35
35
|
- Linux
|
|
36
|
-
- (TODO) Windows
|
|
37
|
-
- (TODO) MacOS
|
|
38
36
|
|
|
39
37
|
## Implemented Structures
|
|
40
38
|
|
|
@@ -122,7 +120,7 @@ string
|
|
|
122
120
|
require 'memory_io'
|
|
123
121
|
process = MemoryIO.attach(`pidof victim`.to_i)
|
|
124
122
|
|
|
125
|
-
# An example that
|
|
123
|
+
# An example that reads a chunk of pt-malloc.
|
|
126
124
|
read_chunk = lambda do |stream|
|
|
127
125
|
_prev_size = stream.read(8)
|
|
128
126
|
size = (stream.read(8).unpack('Q').first & -16) - 8
|
data/lib/memory_io/io.rb
CHANGED
|
@@ -183,7 +183,7 @@ module MemoryIO
|
|
|
183
183
|
# @api private
|
|
184
184
|
def to_proc(as, rw)
|
|
185
185
|
ret = as.respond_to?(rw) ? as.method(rw) : as
|
|
186
|
-
ret =
|
|
186
|
+
ret = MemoryIO::Types.get_proc(ret, rw) unless ret.respond_to?(:call)
|
|
187
187
|
raise ArgumentError, <<-EOERR.strip unless ret.respond_to?(:call)
|
|
188
188
|
|
|
189
189
|
Invalid argument `as`: #{as.inspect}. It should be either a Proc or a supported type of MemoryIO::Types.
|
data/lib/memory_io/process.rb
CHANGED
|
@@ -37,8 +37,8 @@ module MemoryIO
|
|
|
37
37
|
private
|
|
38
38
|
|
|
39
39
|
def unpack(str)
|
|
40
|
-
val = str.
|
|
41
|
-
val -= (2**(@bytes * 8)) if @signed && val >= (2**(@bytes * 8 - 1))
|
|
40
|
+
val = str.unpack1(@pack_str)
|
|
41
|
+
val -= (2**(@bytes * 8)) if @signed && val >= (2**((@bytes * 8) - 1))
|
|
42
42
|
val
|
|
43
43
|
end
|
|
44
44
|
|
|
@@ -22,9 +22,7 @@ module MemoryIO
|
|
|
22
22
|
# std::string uses inlined-buffer if string length isn't larger than {LOCAL_CAPACITY}.
|
|
23
23
|
LOCAL_CAPACITY = 15
|
|
24
24
|
|
|
25
|
-
attr_reader :data # @return [::String]
|
|
26
|
-
attr_reader :capacity # @return [Integer]
|
|
27
|
-
attr_reader :dataplus # @return [Integer]
|
|
25
|
+
attr_reader :data, :capacity, :dataplus # @return [::String] # @return [Integer] # @return [Integer]
|
|
28
26
|
|
|
29
27
|
# Instantiate a {CPP::String} object.
|
|
30
28
|
#
|
|
@@ -33,6 +31,7 @@ module MemoryIO
|
|
|
33
31
|
# @param [Integer] dataplus
|
|
34
32
|
# A pointer.
|
|
35
33
|
def initialize(data, capacity, dataplus)
|
|
34
|
+
super()
|
|
36
35
|
@data = data
|
|
37
36
|
@capacity = capacity
|
|
38
37
|
@dataplus = dataplus
|
|
@@ -57,15 +56,14 @@ module MemoryIO
|
|
|
57
56
|
# Custom inspect view.
|
|
58
57
|
#
|
|
59
58
|
# @return [String]
|
|
60
|
-
#
|
|
61
|
-
# @todo
|
|
62
|
-
# Let it be colorful in pry.
|
|
63
59
|
def inspect
|
|
60
|
+
# rubocop:disable Lint/FormatParameterMismatch
|
|
64
61
|
format("#<%s @data=%s, @capacity=%d, @dataplus=0x%0#{SIZE_T * 2}x>",
|
|
65
62
|
self.class.name,
|
|
66
63
|
data.inspect,
|
|
67
64
|
capacity,
|
|
68
65
|
dataplus)
|
|
66
|
+
# rubocop:enable Lint/FormatParameterMismatch
|
|
69
67
|
end
|
|
70
68
|
|
|
71
69
|
class << self
|
|
@@ -109,10 +107,10 @@ module MemoryIO
|
|
|
109
107
|
write_size_t(stream, obj.length)
|
|
110
108
|
pos = stream.pos
|
|
111
109
|
if obj.length > LOCAL_CAPACITY
|
|
112
|
-
keep_pos(stream, pos: obj.dataplus) { |s| s.write(obj.data
|
|
110
|
+
keep_pos(stream, pos: obj.dataplus) { |s| s.write("#{obj.data}\u0000") }
|
|
113
111
|
write_size_t(stream, obj.capacity)
|
|
114
112
|
else
|
|
115
|
-
stream.write(obj.data
|
|
113
|
+
stream.write("#{obj.data}\u0000")
|
|
116
114
|
end
|
|
117
115
|
stream.pos = pos + LOCAL_CAPACITY + 1
|
|
118
116
|
end
|
|
@@ -23,8 +23,8 @@ module MemoryIO
|
|
|
23
23
|
# @option [Thread::Backtrace::Location] caller
|
|
24
24
|
# This option should present if and only if +object+ is a subclass of {Types::Type}.
|
|
25
25
|
# @option [String] doc
|
|
26
|
-
#
|
|
27
|
-
# Automatically parse from caller location if this parameter
|
|
26
|
+
# Doc-string.
|
|
27
|
+
# Automatically parse from caller location if this parameter doesn't present.
|
|
28
28
|
def initialize(object, keys, option = {})
|
|
29
29
|
@obj = object
|
|
30
30
|
@keys = keys
|
|
@@ -60,14 +60,14 @@ module MemoryIO
|
|
|
60
60
|
str.strip!
|
|
61
61
|
break unless str.start_with?('#')
|
|
62
62
|
|
|
63
|
-
strings.unshift(str[2
|
|
63
|
+
strings.unshift(str[2..] || '')
|
|
64
64
|
end
|
|
65
65
|
trim_docstring(strings)
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def trim_docstring(strings)
|
|
69
69
|
strings = strings.drop_while { |s| s.start_with?('@') }.take_while { |s| !s.start_with?('@') }
|
|
70
|
-
strings.drop_while(&:empty?).reverse.drop_while(&:empty?).reverse.join("\n")
|
|
70
|
+
"#{strings.drop_while(&:empty?).reverse.drop_while(&:empty?).reverse.join("\n")}\n"
|
|
71
71
|
end
|
|
72
72
|
end
|
|
73
73
|
end
|
data/lib/memory_io/types/type.rb
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'ostruct'
|
|
4
|
-
|
|
5
3
|
require 'memory_io/types/record'
|
|
6
4
|
require 'memory_io/util'
|
|
7
5
|
|
|
@@ -123,7 +121,7 @@ module MemoryIO
|
|
|
123
121
|
#
|
|
124
122
|
# @see .find
|
|
125
123
|
def register(object, option = {})
|
|
126
|
-
@map ||=
|
|
124
|
+
@map ||= {}
|
|
127
125
|
aliases = Array(option[:alias])
|
|
128
126
|
reg_fail = ArgumentError.new(<<-EOS.strip)
|
|
129
127
|
Register '#{object.inspect}' fails because another object with same name has been registered.
|
|
@@ -152,6 +150,7 @@ Specify an alias such as `register(MyClass, alias: :custom_alias_name)`.
|
|
|
152
150
|
#
|
|
153
151
|
# To record descendants.
|
|
154
152
|
def inherited(klass)
|
|
153
|
+
super
|
|
155
154
|
register(klass, caller: caller_locations(1, 1).first)
|
|
156
155
|
end
|
|
157
156
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require 'memory_io/types/type'
|
|
4
4
|
require 'memory_io/util'
|
|
5
5
|
|
|
6
|
-
Dir.glob(File.join(__dir__, '**', '*.rb')).
|
|
6
|
+
Dir.glob(File.join(__dir__, '**', '*.rb')).each { |f| require f unless f == __FILE__ }
|
|
7
7
|
|
|
8
8
|
module MemoryIO
|
|
9
9
|
# Module that includes multiple types.
|
|
@@ -33,7 +33,7 @@ module MemoryIO
|
|
|
33
33
|
# #=> #<MemoryIO::Types::Number:0x000055ecc017a310 @bytes=8, @pack_str="Q", @signed=false>
|
|
34
34
|
def find(name)
|
|
35
35
|
obj = Types::Type.find(name)
|
|
36
|
-
|
|
36
|
+
obj&.obj
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
# @api private
|
data/lib/memory_io/util.rb
CHANGED
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'ostruct'
|
|
4
3
|
require 'dentaku'
|
|
5
4
|
|
|
6
5
|
module MemoryIO
|
|
7
6
|
# Defines utility methods.
|
|
8
7
|
module Util
|
|
8
|
+
# A simple class to be returned for getting file permissions.
|
|
9
|
+
class FilePermission
|
|
10
|
+
attr_reader :readable, :writable
|
|
11
|
+
# Alias the two methods to fit Ruby's method naming convention.
|
|
12
|
+
alias readable? readable
|
|
13
|
+
alias writable? writable
|
|
14
|
+
|
|
15
|
+
def initialize(file)
|
|
16
|
+
stat = File.stat(file)
|
|
17
|
+
@readable = stat.readable_real?
|
|
18
|
+
@writable = stat.writable_real?
|
|
19
|
+
# we do a trick here because /proc/[pid]/mem might be marked as writeable but fails at sysopen.
|
|
20
|
+
begin
|
|
21
|
+
@readable && File.open(file, 'rb').close
|
|
22
|
+
rescue Errno::EACCES
|
|
23
|
+
@readable = false
|
|
24
|
+
end
|
|
25
|
+
begin
|
|
26
|
+
@writable && File.open(file, 'wb').close
|
|
27
|
+
rescue Errno::EACCES
|
|
28
|
+
@writable = false
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
9
33
|
module_function
|
|
10
34
|
|
|
11
35
|
# Convert input into snake-case.
|
|
@@ -39,26 +63,12 @@ module MemoryIO
|
|
|
39
63
|
# @param [String] file
|
|
40
64
|
# File name.
|
|
41
65
|
#
|
|
42
|
-
# @return [
|
|
43
|
-
#
|
|
44
|
-
# +nil+ for file not exists or is inaccessible.
|
|
66
|
+
# @return [MemoryIO::Util::FilePermission?]
|
|
67
|
+
# +nil+ is returned if file does not exist or is inaccessible.
|
|
45
68
|
def file_permission(file)
|
|
46
69
|
return nil unless File.file?(file)
|
|
47
70
|
|
|
48
|
-
|
|
49
|
-
# we do a trick here because /proc/[pid]/mem might be marked as readable but fails at sysopen.
|
|
50
|
-
os = OpenStruct.new(readable?: stat.readable_real?, writable?: stat.writable_real?)
|
|
51
|
-
begin
|
|
52
|
-
os.readable? && File.open(file, 'rb').close
|
|
53
|
-
rescue Errno::EACCES
|
|
54
|
-
os[:readable?] = false
|
|
55
|
-
end
|
|
56
|
-
begin
|
|
57
|
-
os.writable? && File.open(file, 'wb').close
|
|
58
|
-
rescue Errno::EACCES
|
|
59
|
-
os[:writable?] = false
|
|
60
|
-
end
|
|
61
|
-
os
|
|
71
|
+
FilePermission.new(file)
|
|
62
72
|
end
|
|
63
73
|
|
|
64
74
|
# Evaluate string safely.
|
|
@@ -97,7 +107,7 @@ module MemoryIO
|
|
|
97
107
|
# Util.unpack("@\xE2\x01\x00")
|
|
98
108
|
# #=> 123456
|
|
99
109
|
def unpack(str)
|
|
100
|
-
str.bytes.reverse.reduce(0) { |s, c| s * 256 + c }
|
|
110
|
+
str.bytes.reverse.reduce(0) { |s, c| (s * 256) + c }
|
|
101
111
|
end
|
|
102
112
|
|
|
103
113
|
# Pack an integer into +b+ bytes.
|
|
@@ -135,9 +145,13 @@ module MemoryIO
|
|
|
135
145
|
# #=> 'libcrypto'
|
|
136
146
|
# Util.trim_libname('not_a_so')
|
|
137
147
|
# #=> 'not_a_so'
|
|
148
|
+
# Util.trim_libname('ld-linux-x86-64.so.2')
|
|
149
|
+
# #=> 'ld'
|
|
138
150
|
def trim_libname(name)
|
|
151
|
+
return 'ld' if name.start_with?('ld-')
|
|
152
|
+
|
|
139
153
|
type1 = '(-[\d.]+)?\.so$'
|
|
140
|
-
type2 = '\.so
|
|
154
|
+
type2 = '\.so.[\.\d]+$'
|
|
141
155
|
name.sub(/#{type1}|#{type2}/, '')
|
|
142
156
|
end
|
|
143
157
|
end
|
data/lib/memory_io/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,29 +1,42 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: memory_io
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- david942j
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 2025-11-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: dentaku
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
|
-
- - "
|
|
16
|
+
- - "~>"
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
18
|
+
version: '3'
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '3'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: ostruct
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0.6'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
22
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
36
|
requirements:
|
|
24
37
|
- - ">="
|
|
25
38
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
39
|
+
version: '0.6'
|
|
27
40
|
- !ruby/object:Gem::Dependency
|
|
28
41
|
name: rake
|
|
29
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -58,28 +71,28 @@ dependencies:
|
|
|
58
71
|
requirements:
|
|
59
72
|
- - "~>"
|
|
60
73
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
74
|
+
version: '1'
|
|
62
75
|
type: :development
|
|
63
76
|
prerelease: false
|
|
64
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
78
|
requirements:
|
|
66
79
|
- - "~>"
|
|
67
80
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
81
|
+
version: '1'
|
|
69
82
|
- !ruby/object:Gem::Dependency
|
|
70
83
|
name: simplecov
|
|
71
84
|
requirement: !ruby/object:Gem::Requirement
|
|
72
85
|
requirements:
|
|
73
86
|
- - "~>"
|
|
74
87
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '0.
|
|
88
|
+
version: '0.22'
|
|
76
89
|
type: :development
|
|
77
90
|
prerelease: false
|
|
78
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
92
|
requirements:
|
|
80
93
|
- - "~>"
|
|
81
94
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '0.
|
|
95
|
+
version: '0.22'
|
|
83
96
|
- !ruby/object:Gem::Dependency
|
|
84
97
|
name: yard
|
|
85
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -96,13 +109,14 @@ dependencies:
|
|
|
96
109
|
version: '0.9'
|
|
97
110
|
description: 'Read/Write complicated structures in memory easily.
|
|
98
111
|
|
|
99
|
-
'
|
|
112
|
+
'
|
|
100
113
|
email:
|
|
101
114
|
- david942j@gmail.com
|
|
102
115
|
executables: []
|
|
103
116
|
extensions: []
|
|
104
117
|
extra_rdoc_files: []
|
|
105
118
|
files:
|
|
119
|
+
- LICENSE
|
|
106
120
|
- README.md
|
|
107
121
|
- lib/memory_io.rb
|
|
108
122
|
- lib/memory_io/io.rb
|
|
@@ -118,8 +132,8 @@ files:
|
|
|
118
132
|
homepage: https://github.com/david942j/memory_io
|
|
119
133
|
licenses:
|
|
120
134
|
- MIT
|
|
121
|
-
metadata:
|
|
122
|
-
|
|
135
|
+
metadata:
|
|
136
|
+
rubygems_mfa_required: 'true'
|
|
123
137
|
rdoc_options: []
|
|
124
138
|
require_paths:
|
|
125
139
|
- lib
|
|
@@ -127,15 +141,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
127
141
|
requirements:
|
|
128
142
|
- - ">="
|
|
129
143
|
- !ruby/object:Gem::Version
|
|
130
|
-
version: '2
|
|
144
|
+
version: '3.2'
|
|
131
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
146
|
requirements:
|
|
133
147
|
- - ">="
|
|
134
148
|
- !ruby/object:Gem::Version
|
|
135
149
|
version: '0'
|
|
136
150
|
requirements: []
|
|
137
|
-
rubygems_version: 3.
|
|
138
|
-
signing_key:
|
|
151
|
+
rubygems_version: 3.6.2
|
|
139
152
|
specification_version: 4
|
|
140
153
|
summary: memory_io
|
|
141
154
|
test_files: []
|