marshal-parser 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|