tcepsni 0.1.1 → 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 +19 -0
- data/lib/tcepsni/version.rb +1 -1
- data/lib/tcepsni.rb +124 -34
- data/sig/tcepsni.gen.rbs +30 -11
- data/sig/tcepsni.rbs +23 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3695b6a1a12979fa76824819d4f839ce4e3b9a2af040f97eca9e474609c5c1f2
|
4
|
+
data.tar.gz: 373da53b2e230d3510f2043f25b8ae7cf017fae689fdfbaa92a388be4155ebcd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f646aecf1094e4e171581b52ca0e48dccddc4464bf158f4c30b93e8df7ef7b8989b240e9c61abf25a7cb65c2c9a29ec6978529f627a1c360f0fede299624d297
|
7
|
+
data.tar.gz: 573e5e82c5c7a0b476ee93255fe6b6fc7992febcee911e54ee1b852c9acacca29950bc67183ec01cbed7c3cf3cfcce3edd21137f1c04400bff42959d6f1d72c8
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,25 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## 0.2.0 - 2023-10-20
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- `Time` support
|
10
|
+
- `Pathname` support
|
11
|
+
- `Encoding` support
|
12
|
+
- `IPAddr` support
|
13
|
+
- `ActiveSupport::OrderedOptions` support
|
14
|
+
- `Rails::Paths::Root` support
|
15
|
+
- `Float` support
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
|
19
|
+
- Parsing the empty array
|
20
|
+
- Parsing the object with some attributes
|
21
|
+
- Parsing the `nil`, `true`, and `false` literals
|
22
|
+
- Detecting `StringScanner`-like object
|
23
|
+
|
5
24
|
## 0.1.1 - 2023-10-02
|
6
25
|
|
7
26
|
### Changed
|
data/lib/tcepsni/version.rb
CHANGED
data/lib/tcepsni.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
require 'strscan'
|
2
|
+
require 'pathname'
|
3
|
+
require 'ipaddr'
|
4
|
+
require 'active_support/ordered_options'
|
5
|
+
require 'rails/paths'
|
2
6
|
require_relative 'tcepsni/version'
|
3
7
|
|
4
8
|
module Tcepsni
|
@@ -14,11 +18,11 @@ module Tcepsni
|
|
14
18
|
|
15
19
|
# If it returned nil when failed, it collides with normal nil value.
|
16
20
|
def parse_expression(scanner)
|
17
|
-
if scanner.skip(
|
21
|
+
if scanner.skip(/nil\b/)
|
18
22
|
nil
|
19
|
-
elsif scanner.skip(
|
23
|
+
elsif scanner.skip(/true\b/)
|
20
24
|
true
|
21
|
-
elsif scanner.skip(
|
25
|
+
elsif scanner.skip(/false\b/)
|
22
26
|
false
|
23
27
|
elsif scanner.skip(':')
|
24
28
|
parse_identifier(scanner)
|
@@ -31,14 +35,26 @@ module Tcepsni
|
|
31
35
|
elsif scanner.skip('#<')
|
32
36
|
parse_object(scanner)
|
33
37
|
else
|
34
|
-
|
38
|
+
if (digits = scanner.scan(/\d+/))
|
39
|
+
int = Integer(digits)
|
40
|
+
if scanner.skip('.')
|
41
|
+
int2 = parse_integer(scanner)
|
42
|
+
Float("#{int}.#{int2}")
|
43
|
+
elsif digits.size == 4 && scanner.skip(/-(?<month>[01]\d)-(?<day>\d\d) (?<hour>[012]\d):(?<minute>[0-5]\d):(?<second>[0-5]\d) (?<zone>[+-]\d\d\d\d)/)
|
44
|
+
Time.new(Integer(int), scanner[:month], scanner[:day],
|
45
|
+
scanner[:hour], scanner[:minute], scanner[:second],
|
46
|
+
scanner[:zone])
|
47
|
+
else
|
48
|
+
int
|
49
|
+
end
|
50
|
+
else
|
51
|
+
parse_class(scanner)
|
52
|
+
end
|
35
53
|
end
|
36
54
|
end
|
37
55
|
|
38
|
-
# Returns nil if it's not integer.
|
39
|
-
# This doesn't raise error for convenience.
|
40
56
|
def parse_integer(scanner)
|
41
|
-
int = scanner.scan(/\d+/) or
|
57
|
+
int = scanner.scan(/\d+/) or raise Error, 'no digits'
|
42
58
|
Integer(int)
|
43
59
|
end
|
44
60
|
|
@@ -62,13 +78,12 @@ module Tcepsni
|
|
62
78
|
end
|
63
79
|
|
64
80
|
def parse_array(scanner)
|
65
|
-
result = [
|
81
|
+
result = []
|
66
82
|
until scanner.eos?
|
83
|
+
result << parse_expression(scanner) rescue break
|
67
84
|
scanner.skip(', ') or break
|
68
|
-
scanner.eos? and raise Error, 'incomplete array'
|
69
|
-
result << parse_expression(scanner)
|
70
85
|
end
|
71
|
-
scanner.skip(']') or raise Error,
|
86
|
+
scanner.skip(']') or raise Error, "no array closer: #{scanner.inspect}"
|
72
87
|
result
|
73
88
|
end
|
74
89
|
|
@@ -97,7 +112,7 @@ module Tcepsni
|
|
97
112
|
end
|
98
113
|
|
99
114
|
def parse_capitalized_identifier(scanner)
|
100
|
-
id = scanner.scan(/[A-Z][A-Za-z0-9_]*/) or raise Error,
|
115
|
+
id = scanner.scan(/[A-Z][A-Za-z0-9_]*/) or raise Error, "no capitalized identifier: #{scanner.inspect}"
|
101
116
|
id.intern
|
102
117
|
end
|
103
118
|
|
@@ -105,30 +120,70 @@ module Tcepsni
|
|
105
120
|
klass = parse_class(scanner)
|
106
121
|
if klass.string_scanner?
|
107
122
|
scanner.skip(' ') or raise Error, 'no space after string scanner class name'
|
108
|
-
pos = parse_integer(scanner)
|
123
|
+
pos = parse_integer(scanner)
|
109
124
|
scanner.skip('/') or raise Error, 'no string scanner progress delimiter slash'
|
110
|
-
total = parse_integer(scanner)
|
125
|
+
total = parse_integer(scanner)
|
111
126
|
scanner.skip(' "') or raise Error, 'no space after string scanner progress'
|
112
127
|
scanned = parse_string(scanner)
|
113
128
|
scanner.skip(' @ "') or raise Error, "no string scanner mark in string: #{scanner.inspect}"
|
114
129
|
rest = parse_string(scanner)
|
115
130
|
scanner.skip('>') or raise Error, 'no string scanner closer'
|
116
|
-
Tcepsni::StringScanner.new(pos: pos, total: total, scanned: scanned, rest: rest)
|
131
|
+
Tcepsni::Vendor::StringScanner.new(pos: pos, total: total, scanned: scanned, rest: rest)
|
132
|
+
elsif klass.pathname?
|
133
|
+
scanner.skip(':') or raise Error, 'no colon between Pathname class name and path string'
|
134
|
+
scanner.skip(/(?<path>[^>]+)>/) or raise Error, 'invalid path string and closer'
|
135
|
+
Pathname(scanner[:path])
|
136
|
+
elsif klass.encoding?
|
137
|
+
scanner.skip(':') or raise Error, 'no colon separator in encoding object'
|
138
|
+
scanner.skip(/(?<name>[^>]+)>/) or raise Error, 'invalid encoding name'
|
139
|
+
Encoding.find(scanner[:name])
|
140
|
+
elsif klass.ipaddr?
|
141
|
+
scanner.skip(/: IPv[46]:(?<addr>[^>]+)>/) or raise Error, 'invalid IP address format error'
|
142
|
+
IPAddr.new(scanner[:addr])
|
143
|
+
elsif klass.active_support_ordered_options?
|
144
|
+
scanner.skip(' {') or raise Error, 'no space between ActiveSupport::OrderedOptions class name and hash opener'
|
145
|
+
hash = parse_hash(scanner)
|
146
|
+
scanner.skip('>') or raise Error, "no ActiveSupport ordered options closer: #{scanner.inspect}"
|
147
|
+
options = ActiveSupport::OrderedOptions.new
|
148
|
+
hash.each do |key, val|
|
149
|
+
options[key] = val
|
150
|
+
end
|
151
|
+
options
|
152
|
+
elsif klass.rails_paths_root?
|
153
|
+
memory_reference = parse_memory_reference(scanner)
|
154
|
+
if scanner.skip(' ...>')
|
155
|
+
attributes = {}
|
156
|
+
else
|
157
|
+
attributes = parse_attributes(scanner)
|
158
|
+
end
|
159
|
+
Tcepsni::Vendor::Rails::Paths::Root.new(memory_reference, attributes)
|
117
160
|
else
|
118
|
-
|
119
|
-
|
120
|
-
attributes
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
161
|
+
memory_reference = parse_memory_reference(scanner)
|
162
|
+
attributes = parse_attributes(scanner)
|
163
|
+
Tcepsni::Object.new(klass: klass, memory_reference: memory_reference, attributes: attributes)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def parse_attributes(scanner)
|
168
|
+
attributes = {}
|
169
|
+
unless scanner.skip('>')
|
170
|
+
until scanner.eos?
|
171
|
+
scanner.skip(' @') or break
|
172
|
+
key = parse_identifier(scanner)
|
173
|
+
scanner.skip('=') or raise Error, 'no attribute keyval equal char'
|
174
|
+
attributes[key.intern] = parse_expression(scanner)
|
175
|
+
unless scanner.skip(',')
|
176
|
+
scanner.skip('>') or raise Error, "no object closer: #{scanner.inspect}"
|
177
|
+
break
|
128
178
|
end
|
129
179
|
end
|
130
|
-
Tcepsni::Object.new(klass: klass, memory_reference: memory_reference, attributes: attributes)
|
131
180
|
end
|
181
|
+
attributes
|
182
|
+
end
|
183
|
+
|
184
|
+
def parse_memory_reference(scanner)
|
185
|
+
scanner.skip(/:(?<memory_reference>0x[0-9a-f]{16})/) or raise Error, "no memory reference: #{scanner.inspect}"
|
186
|
+
Integer(scanner[:memory_reference])
|
132
187
|
end
|
133
188
|
end
|
134
189
|
|
@@ -141,7 +196,27 @@ module Tcepsni
|
|
141
196
|
end
|
142
197
|
|
143
198
|
def string_scanner?
|
144
|
-
|
199
|
+
@name == :StringScanner && @namespaces.empty?
|
200
|
+
end
|
201
|
+
|
202
|
+
def pathname?
|
203
|
+
@name == :Pathname
|
204
|
+
end
|
205
|
+
|
206
|
+
def encoding?
|
207
|
+
@name == :Encoding && @namespaces.empty?
|
208
|
+
end
|
209
|
+
|
210
|
+
def ipaddr?
|
211
|
+
@name == :IPAddr && @namespaces.empty?
|
212
|
+
end
|
213
|
+
|
214
|
+
def active_support_ordered_options?
|
215
|
+
@name == :OrderedOptions && @namespaces == [:ActiveSupport]
|
216
|
+
end
|
217
|
+
|
218
|
+
def rails_paths_root?
|
219
|
+
@name == :Root && @namespaces == [:Rails, :Paths]
|
145
220
|
end
|
146
221
|
end
|
147
222
|
|
@@ -155,14 +230,29 @@ module Tcepsni
|
|
155
230
|
end
|
156
231
|
end
|
157
232
|
|
158
|
-
|
159
|
-
|
233
|
+
module Vendor
|
234
|
+
class StringScanner
|
235
|
+
attr_reader :pos, :total, :scanned, :rest
|
160
236
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
237
|
+
def initialize(pos:, total:, scanned:, rest:)
|
238
|
+
@pos = pos
|
239
|
+
@total = total
|
240
|
+
@scanned = scanned
|
241
|
+
@rest = rest
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
module Rails
|
246
|
+
module Paths
|
247
|
+
class Root
|
248
|
+
attr_reader :memory_reference, :attributes
|
249
|
+
|
250
|
+
def initialize(memory_reference, attributes)
|
251
|
+
@memory_reference = memory_reference
|
252
|
+
@attributes = attributes
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
166
256
|
end
|
167
257
|
end
|
168
258
|
end
|
data/sig/tcepsni.gen.rbs
CHANGED
@@ -5,20 +5,27 @@ module Tcepsni
|
|
5
5
|
VERSION: String
|
6
6
|
|
7
7
|
# def self.parse: (String str) -> parsed
|
8
|
-
def self.parse_expression: (untyped scanner) -> ((Array[(Array[(Class | Integer | Object | String |
|
9
|
-
def self.parse_integer: (untyped scanner) -> Integer
|
8
|
+
def self.parse_expression: (untyped scanner) -> ((Array[(Array[(Class | Float | Integer | Object | String | Time | bool)?] | Hash[Object?, Object?] | Object)?] | Hash[Object?, (Array[Object?] | Hash[Object?, Object?] | Object)?] | Object)?)
|
9
|
+
def self.parse_integer: (untyped scanner) -> Integer
|
10
10
|
def self.parse_identifier: (untyped scanner) -> untyped
|
11
11
|
def self.parse_string: (untyped scanner) -> String
|
12
|
-
def self.parse_array: (untyped scanner) -> (Array[(Array[(Array[untyped] | Class | Hash[(Class | Integer | Object | String |
|
13
|
-
def self.parse_hash: (untyped scanner) -> (Hash[
|
12
|
+
def self.parse_array: (untyped scanner) -> (Array[(Array[(Array[untyped] | Class | Float | Hash[(Class | Float | Integer | Object | String | Time | bool)?, untyped] | Integer | Object | String | Time | bool)?] | Hash[Object?, (Array[untyped] | Hash[Object?, untyped] | Object)?] | Object)?])
|
13
|
+
def self.parse_hash: (untyped scanner) -> (Hash[Object?, (Array[(Array[untyped] | Hash[Object?, untyped] | Object)?] | Hash[Object?, (Array[untyped] | Hash[Object?, untyped] | Object)?] | Object)?])
|
14
14
|
def self.parse_class: (untyped scanner) -> Class
|
15
15
|
def self.parse_capitalized_identifier: (untyped scanner) -> untyped
|
16
|
-
def self.parse_object: (untyped scanner) -> (Object | StringScanner)
|
16
|
+
def self.parse_object: (untyped scanner) -> (Encoding | IPAddr | Object | Pathname | Vendor::Rails::Paths::Root | Vendor::StringScanner)
|
17
|
+
def self.parse_attributes: (untyped scanner) -> (Hash[untyped, (Array[(Array[untyped] | Hash[Object?, untyped] | Object)?] | Hash[Object?, (Array[untyped] | Hash[Object?, untyped] | Object)?] | Object)?])
|
18
|
+
def self.parse_memory_reference: (untyped scanner) -> Integer
|
17
19
|
|
18
20
|
class Class
|
19
21
|
# def initialize: (name: Symbol?, namespaces: Array[Symbol]) -> void
|
20
22
|
# def ==: (Class other) -> bool
|
21
23
|
# def string_scanner?: -> bool
|
24
|
+
# def pathname?: -> bool
|
25
|
+
# def encoding?: -> bool
|
26
|
+
# def ipaddr?: -> bool
|
27
|
+
# def active_support_ordered_options?: -> bool
|
28
|
+
# def rails_paths_root?: -> bool
|
22
29
|
# attr_reader name: Symbol?
|
23
30
|
# attr_reader namespaces: Array[Symbol]
|
24
31
|
end
|
@@ -30,11 +37,23 @@ module Tcepsni
|
|
30
37
|
# attr_reader memory_reference: Integer
|
31
38
|
end
|
32
39
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
40
|
+
module Vendor
|
41
|
+
class StringScanner
|
42
|
+
# def initialize: (pos: Integer, total: Integer, scanned: String, rest: String) -> void
|
43
|
+
# attr_reader pos: Integer
|
44
|
+
# attr_reader total: Integer
|
45
|
+
# attr_reader scanned: String
|
46
|
+
# attr_reader rest: String
|
47
|
+
end
|
48
|
+
|
49
|
+
module Rails
|
50
|
+
module Paths
|
51
|
+
class Root
|
52
|
+
# def initialize: (Integer memory_reference, Hash[Symbol, parsed?] attributes) -> void
|
53
|
+
# attr_reader memory_reference: Integer
|
54
|
+
# attr_reader attributes: Hash[Symbol, (Array[untyped] | Array[untyped] | Class | Hash[untyped, untyped] | Hash[untyped, untyped] | Integer | Object | String | StringScanner | Symbol | bool)?]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
39
58
|
end
|
40
59
|
end
|
data/sig/tcepsni.rbs
CHANGED
@@ -16,6 +16,11 @@ module Tcepsni
|
|
16
16
|
def initialize: (name: Symbol?, namespaces: Array[Symbol]) -> void
|
17
17
|
def ==: (Class other) -> bool
|
18
18
|
def string_scanner?: -> bool
|
19
|
+
def pathname?: -> bool
|
20
|
+
def encoding?: -> bool
|
21
|
+
def ipaddr?: -> bool
|
22
|
+
def active_support_ordered_options?: -> bool
|
23
|
+
def rails_paths_root?: -> bool
|
19
24
|
end
|
20
25
|
|
21
26
|
class Object
|
@@ -25,11 +30,23 @@ module Tcepsni
|
|
25
30
|
def initialize: (klass: Class, attributes: Hash[Symbol, parsed], memory_reference: Integer) -> void
|
26
31
|
end
|
27
32
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
module Vendor
|
34
|
+
class StringScanner
|
35
|
+
attr_reader pos: Integer
|
36
|
+
attr_reader total: Integer
|
37
|
+
attr_reader scanned: String
|
38
|
+
attr_reader rest: String
|
39
|
+
def initialize: (pos: Integer, total: Integer, scanned: String, rest: String) -> void
|
40
|
+
end
|
41
|
+
|
42
|
+
module Rails
|
43
|
+
module Paths
|
44
|
+
class Root
|
45
|
+
attr_reader memory_reference: Integer
|
46
|
+
attr_reader attributes: Hash[Symbol, parsed?]
|
47
|
+
def initialize: (Integer memory_reference, Hash[Symbol, parsed?] attributes) -> void
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
34
51
|
end
|
35
52
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tcepsni
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- gemmaro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10-
|
11
|
+
date: 2023-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Tcepsni gem is a parser library for inspected strings of Ruby objects.
|
14
14
|
email:
|