marshal-parser 0.1.0 → 0.2.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/CHANGELOG.md +13 -1
- data/README.md +5 -5
- data/lib/marshal-parser/cli/commands.rb +13 -2
- data/lib/marshal-parser/formatters/tokens/one_line.rb +13 -5
- data/lib/marshal-parser/formatters/tokens/with_description.rb +14 -3
- data/lib/marshal-parser/lexer.rb +8 -1
- data/lib/marshal-parser/parser.rb +1 -2
- data/lib/marshal-parser/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 84d834a71863bd08ec4f6a4027ddac9603dd83bf5cfa7c0f7c81b540e43950b9
|
|
4
|
+
data.tar.gz: b2327a3176bc5b31db011b61d79d13aa2b973a98596bd9a5586376617a1407cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 505dd53a7648131070bb260a26c1c86a38d057f0e9c84539dd02bef8571f828f7b48e42a463fdb75d9eb0088379f7725c8432748bdf8b829023cf07587638194
|
|
7
|
+
data.tar.gz: 22bce0b7a72769507db2d612d179a2d82fb0376319f63d062ff41a1ce907cb7bfcf1cadc141355e33ad3ab863284d07611c030053f1f1a4c6e094636fcbdf824
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.2.0] - 2023-12-20
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Added `--hex` flag to print tokens in hexadecimal encoding
|
|
8
|
+
- Added `-r`/`--require` option to load Ruby source file
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Fixed parsing of a Hash with default value
|
|
13
|
+
- Fixed parsing of a Regexp with options
|
|
14
|
+
|
|
3
15
|
## [0.1.0] - 2023-02-27
|
|
4
16
|
|
|
5
|
-
|
|
17
|
+
Initial release
|
data/README.md
CHANGED
|
@@ -31,7 +31,7 @@ Ruby object.
|
|
|
31
31
|
|
|
32
32
|
The Marshal format is described here <https://ruby-doc.org/core-3.1.0/doc/marshal_rdoc.html>.
|
|
33
33
|
|
|
34
|
-
There are also a lot of useful
|
|
34
|
+
There are also a lot of articles that could be useful, for instance:
|
|
35
35
|
- <https://shopify.engineering/caching-without-marshal-part-one>
|
|
36
36
|
- <https://iliabylich.github.io/2016/01/25/ruby-marshalling-from-a-to-z.html>
|
|
37
37
|
- <http://jakegoulding.com/blog/categories/marshal/>
|
|
@@ -160,7 +160,7 @@ lexer.run
|
|
|
160
160
|
parser = MarshalParser::Parser.new(lexer)
|
|
161
161
|
ast = parser.parse
|
|
162
162
|
|
|
163
|
-
|
|
163
|
+
pp ast
|
|
164
164
|
```
|
|
165
165
|
|
|
166
166
|
This will output:
|
|
@@ -171,11 +171,11 @@ This will output:
|
|
|
171
171
|
|
|
172
172
|
## Limitations
|
|
173
173
|
|
|
174
|
-
-
|
|
175
|
-
- Does not support a deprecated node 'M' (that represents Class or Module)
|
|
174
|
+
- Supports only the current Marshal format version (4.8)
|
|
175
|
+
- Does not support a deprecated node 'M' (that represents 'Class or Module')
|
|
176
176
|
- Does not support a 'd' node (Data object, that represents wrapped pointers from Ruby extensions)
|
|
177
177
|
- Doesn't print in annotations object indices (because Ruby is not consistent here and object indices assigning order may
|
|
178
|
-
vary depending on dumped
|
|
178
|
+
vary depending on a class of a dumped object)
|
|
179
179
|
|
|
180
180
|
## Similar projects
|
|
181
181
|
|
|
@@ -11,9 +11,15 @@ module MarshalParser
|
|
|
11
11
|
desc "Parse a dump and print tokens. By default reads dump from the stdin."
|
|
12
12
|
option :file, type: :string, aliases: ["-f"], desc: "Read a dump from file with provided name"
|
|
13
13
|
option :evaluate, type: :string, aliases: ["-e"], desc: "Ruby expression to dump"
|
|
14
|
+
option :require, type: :string, aliases: ["-r"], desc: "Load the library using require. It is useful when -e is specified"
|
|
14
15
|
option :annotate, type: :boolean, aliases: ["-a"], desc: "Print a table with annonated tokens"
|
|
16
|
+
option :hex, type: :boolean, aliases: ["-x"], desc: "Print tokens in a hexadecimal encoding"
|
|
15
17
|
|
|
16
18
|
def call(**options)
|
|
19
|
+
if options[:require]
|
|
20
|
+
require options[:require]
|
|
21
|
+
end
|
|
22
|
+
|
|
17
23
|
dump = \
|
|
18
24
|
if options[:file]
|
|
19
25
|
File.read(options[:file])
|
|
@@ -28,9 +34,9 @@ module MarshalParser
|
|
|
28
34
|
|
|
29
35
|
formatter = \
|
|
30
36
|
if options[:annotate]
|
|
31
|
-
MarshalParser::Formatters::Tokens::WithDescription.new(lexer.tokens, dump)
|
|
37
|
+
MarshalParser::Formatters::Tokens::WithDescription.new(lexer.tokens, dump, hex: options[:hex])
|
|
32
38
|
else
|
|
33
|
-
MarshalParser::Formatters::Tokens::OneLine.new(lexer.tokens, dump)
|
|
39
|
+
MarshalParser::Formatters::Tokens::OneLine.new(lexer.tokens, dump, hex: options[:hex])
|
|
34
40
|
end
|
|
35
41
|
|
|
36
42
|
puts formatter.string
|
|
@@ -41,6 +47,7 @@ module MarshalParser
|
|
|
41
47
|
desc "Parse a dump and print AST. By default reads dump from the stdin and uses S-expressions format."
|
|
42
48
|
option :file, type: :string, aliases: ["-f"], desc: "Read a dump from file with provided name"
|
|
43
49
|
option :evaluate, type: :string, aliases: ["-e"], desc: "Ruby expression to dump"
|
|
50
|
+
option :require, type: :string, aliases: ["-r"], desc: "Load the library using require. It is useful when -e is specified"
|
|
44
51
|
option :"only-tokens", type: :boolean, aliases: ["-o"], desc: "Print only tokens"
|
|
45
52
|
option :annotate, type: :boolean, aliases: ["-a"], desc: "Print annotations"
|
|
46
53
|
option :width, type: :string, aliases: ["-w"],
|
|
@@ -49,6 +56,10 @@ module MarshalParser
|
|
|
49
56
|
option :compact, type: :boolean, aliases: ["-c"], desc: "Don't print node attributes"
|
|
50
57
|
|
|
51
58
|
def call(**options)
|
|
59
|
+
if options[:require]
|
|
60
|
+
require options[:require]
|
|
61
|
+
end
|
|
62
|
+
|
|
52
63
|
dump = \
|
|
53
64
|
if options[:file]
|
|
54
65
|
File.read(options[:file])
|
|
@@ -4,16 +4,24 @@ module MarshalParser
|
|
|
4
4
|
module Formatters
|
|
5
5
|
module Tokens
|
|
6
6
|
class OneLine
|
|
7
|
-
def initialize(tokens, source_string)
|
|
7
|
+
def initialize(tokens, source_string, hex: nil)
|
|
8
8
|
@tokens = tokens
|
|
9
9
|
@source_string = source_string
|
|
10
|
+
@hex = hex
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def string
|
|
13
|
-
@
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
unless @hex
|
|
15
|
+
@tokens.map do |token|
|
|
16
|
+
string = @source_string[token.index, token.length]
|
|
17
|
+
string =~ /[^[:print:]]/ ? string.dump : string
|
|
18
|
+
end.join(" ")
|
|
19
|
+
else
|
|
20
|
+
@tokens.map do |token|
|
|
21
|
+
string = @source_string[token.index, token.length]
|
|
22
|
+
string = string.bytes.map { |b| "%02X" % b }.join(" ")
|
|
23
|
+
end.join(" ")
|
|
24
|
+
end
|
|
17
25
|
end
|
|
18
26
|
end
|
|
19
27
|
end
|
|
@@ -4,14 +4,15 @@ module MarshalParser
|
|
|
4
4
|
module Formatters
|
|
5
5
|
module Tokens
|
|
6
6
|
class WithDescription
|
|
7
|
-
def initialize(tokens, source_string)
|
|
7
|
+
def initialize(tokens, source_string, hex: nil)
|
|
8
8
|
@tokens = tokens
|
|
9
9
|
@source_string = source_string
|
|
10
|
+
@hex = hex
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def string
|
|
13
14
|
@tokens.map do |token|
|
|
14
|
-
string =
|
|
15
|
+
string = token_to_string(token)
|
|
15
16
|
description = self.class.token_description(token.id)
|
|
16
17
|
value = token.value ? " (#{token.value})" : ""
|
|
17
18
|
|
|
@@ -19,6 +20,15 @@ module MarshalParser
|
|
|
19
20
|
end.join("\n")
|
|
20
21
|
end
|
|
21
22
|
|
|
23
|
+
private def token_to_string(token)
|
|
24
|
+
unless @hex
|
|
25
|
+
@source_string[token.index, token.length].dump
|
|
26
|
+
else
|
|
27
|
+
string = @source_string[token.index, token.length]
|
|
28
|
+
string.bytes.map { |b| "%02X" % b }.join(" ")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
22
32
|
def self.token_description(token)
|
|
23
33
|
case token
|
|
24
34
|
when Lexer::VERSION then "Version"
|
|
@@ -28,7 +38,7 @@ module MarshalParser
|
|
|
28
38
|
when Lexer::OBJECT_WITH_MARSHAL_DUMP_PREFIX then "Object with #marshal_dump and #marshal_load"
|
|
29
39
|
when Lexer::STRING_PREFIX then "String beginning"
|
|
30
40
|
when Lexer::HASH_PREFIX then "Hash beginning"
|
|
31
|
-
when Lexer::HASH_WITH_DEFAULT_VALUE_PREFIX then "Hash beginning (with
|
|
41
|
+
when Lexer::HASH_WITH_DEFAULT_VALUE_PREFIX then "Hash beginning (with default value)"
|
|
32
42
|
when Lexer::REGEXP_PREFIX then "Regexp beginning"
|
|
33
43
|
when Lexer::STRUCT_PREFIX then "Struct beginning"
|
|
34
44
|
when Lexer::TRUE then "true"
|
|
@@ -48,6 +58,7 @@ module MarshalParser
|
|
|
48
58
|
when Lexer::FLOAT then "Float string representation"
|
|
49
59
|
when Lexer::INTEGER then "Integer encoded"
|
|
50
60
|
when Lexer::BIG_INTEGER then "Big Integer encoded"
|
|
61
|
+
when Lexer::BYTE then "Byte"
|
|
51
62
|
when Lexer::STRING then "String characters"
|
|
52
63
|
when Lexer::SYMBOL then "Symbol characters"
|
|
53
64
|
when Lexer::PLUS_SIGN then "Sign '+'"
|
data/lib/marshal-parser/lexer.rb
CHANGED
|
@@ -30,6 +30,7 @@ module MarshalParser
|
|
|
30
30
|
FLOAT,
|
|
31
31
|
INTEGER,
|
|
32
32
|
BIG_INTEGER,
|
|
33
|
+
BYTE,
|
|
33
34
|
STRING,
|
|
34
35
|
SYMBOL,
|
|
35
36
|
PLUS_SIGN,
|
|
@@ -147,6 +148,12 @@ module MarshalParser
|
|
|
147
148
|
elements = (1..count).map { read }
|
|
148
149
|
end
|
|
149
150
|
|
|
151
|
+
def read_byte
|
|
152
|
+
value = @dump[@index].ord
|
|
153
|
+
@index += 1
|
|
154
|
+
@tokens << Token.new(BYTE, @index - 1, 1, value)
|
|
155
|
+
end
|
|
156
|
+
|
|
150
157
|
def read_integer
|
|
151
158
|
index_base = @index
|
|
152
159
|
|
|
@@ -266,7 +273,7 @@ module MarshalParser
|
|
|
266
273
|
|
|
267
274
|
def read_regexp
|
|
268
275
|
read_string # read Regexp's source
|
|
269
|
-
|
|
276
|
+
read_byte # read flags
|
|
270
277
|
end
|
|
271
278
|
|
|
272
279
|
def read_struct
|
|
@@ -130,7 +130,6 @@ module MarshalParser
|
|
|
130
130
|
end
|
|
131
131
|
|
|
132
132
|
default_value_node = build_ast_node
|
|
133
|
-
assert_node_type default_value_node, IntegerNode
|
|
134
133
|
|
|
135
134
|
HashWithDefaultValueNode.new(token, size, key_and_value_nodes, default_value_node)
|
|
136
135
|
|
|
@@ -649,7 +648,7 @@ module MarshalParser
|
|
|
649
648
|
assert_token_type prefix, Lexer::REGEXP_PREFIX
|
|
650
649
|
assert_token_type string_length, Lexer::INTEGER
|
|
651
650
|
assert_token_type string, Lexer::STRING
|
|
652
|
-
assert_token_type options, Lexer::
|
|
651
|
+
assert_token_type options, Lexer::BYTE
|
|
653
652
|
|
|
654
653
|
@prefix = prefix
|
|
655
654
|
@string_length = string_length
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: marshal-parser
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Konchin
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-12-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: dry-cli
|
|
@@ -78,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
78
78
|
- !ruby/object:Gem::Version
|
|
79
79
|
version: '0'
|
|
80
80
|
requirements: []
|
|
81
|
-
rubygems_version: 3.4.
|
|
81
|
+
rubygems_version: 3.4.10
|
|
82
82
|
signing_key:
|
|
83
83
|
specification_version: 4
|
|
84
84
|
summary: Parser of the Ruby Marshal format
|