wurm 0.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/README.md +221 -0
- data/lib/wurm.rb +62 -0
- data/lib/wurm2.rb +45 -0
- metadata +72 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8a44f02498b11753018c46aef5ea14d106138176038977b3211ccab82f170037
|
|
4
|
+
data.tar.gz: bffa1c99607dea7216111c4a35bfeed5010ce766859fd674f173ea595435c4b8
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 3ab658556fb75c646b5c3db2c7b16bc2e3e14335733d88a17d0c1c8ae351a70b56b7568cc3499b3447ccf4d6e662f3db66185b569d6374ac34d42e28d6946860
|
|
7
|
+
data.tar.gz: a41706e65aacbcc70d0e21ef90e4a5103f3fb4bba34e187ea838724daf6e3893ac233bc931a0ed57058c24c91f9890f6f938098bc4efd5e3a265e7c53ae36a94
|
data/README.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Wurm
|
|
2
|
+
|
|
3
|
+
[](https://rubygems.org/gems/wurm)
|
|
4
|
+
[](https://rubygems.org/gems/wurm)
|
|
5
|
+
[](https://github.com/matique/wurm/actions/workflows/rake.yml)
|
|
6
|
+
[](https://github.com/standardrb/standard)
|
|
7
|
+
[](http://choosealicense.com/licenses/mit/)
|
|
8
|
+
|
|
9
|
+
*Wurm* is a lightweight recursive pretty printer for Ruby objects.
|
|
10
|
+
|
|
11
|
+
It displays the structure of Ruby objects in a readable, indented format,
|
|
12
|
+
including nested hashes, arrays, structs, and custom objects.
|
|
13
|
+
|
|
14
|
+
*Wurm* also detects circular references and shared object references,
|
|
15
|
+
preventing infinite recursion
|
|
16
|
+
and making complex object graphs easier to inspect.
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- Recursive inspection of Ruby objects.
|
|
21
|
+
- Support for Hash, Array, and Struct.
|
|
22
|
+
- Support for custom objects through a *wurm* method.
|
|
23
|
+
- Circular reference detection.
|
|
24
|
+
- Shared object reference detection.
|
|
25
|
+
- Object class and object ID information.
|
|
26
|
+
- Special formatting for Date, DateTime, and Time.
|
|
27
|
+
- Configurable output destination through an IO object.
|
|
28
|
+
- No external runtime dependencies.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
As usual:
|
|
34
|
+
|
|
35
|
+
~~~~ruby
|
|
36
|
+
# Gemfile
|
|
37
|
+
...
|
|
38
|
+
gem "wurm"
|
|
39
|
+
...
|
|
40
|
+
~~~~
|
|
41
|
+
|
|
42
|
+
and run "bundle install".
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
## Basic example
|
|
46
|
+
|
|
47
|
+
~~~~ruby
|
|
48
|
+
require "wurm"
|
|
49
|
+
...
|
|
50
|
+
Wurm.pp("Hello World")
|
|
51
|
+
Wurm.pp("legend", "Hello World")
|
|
52
|
+
...
|
|
53
|
+
~~~~
|
|
54
|
+
|
|
55
|
+
Output:
|
|
56
|
+
~~~~ruby
|
|
57
|
+
--- "Hello World"
|
|
58
|
+
Legend "Hello World"
|
|
59
|
+
~~~~
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
## Hashes and arrays
|
|
63
|
+
~~~~ruby
|
|
64
|
+
data = {
|
|
65
|
+
name: "Alice",
|
|
66
|
+
age: 30,
|
|
67
|
+
address: {
|
|
68
|
+
city: "Berlin",
|
|
69
|
+
country: "Germany"
|
|
70
|
+
},
|
|
71
|
+
hobbies: ["Ruby", "Programming"]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
Wurm.pp(data)
|
|
75
|
+
~~~~
|
|
76
|
+
|
|
77
|
+
Output:
|
|
78
|
+
~~~~ruby
|
|
79
|
+
--- <Hash ID: 0x5a8>
|
|
80
|
+
name: "Alice"
|
|
81
|
+
age: 30
|
|
82
|
+
address: <Hash ID: 0x5b0>
|
|
83
|
+
city: "Berlin"
|
|
84
|
+
country: "Germany"
|
|
85
|
+
hobbies: <Array ID: 0x5b8>
|
|
86
|
+
[0] "Ruby"
|
|
87
|
+
[1] "Programming"
|
|
88
|
+
~~~~
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## Custom objects
|
|
92
|
+
|
|
93
|
+
Custom objects can define a *wurm* method that returns an array of
|
|
94
|
+
attribute names to inspect.
|
|
95
|
+
|
|
96
|
+
~~~~ruby
|
|
97
|
+
class Person
|
|
98
|
+
attr_accessor :name, :age, :address
|
|
99
|
+
|
|
100
|
+
def initialize(name, age, address)
|
|
101
|
+
@name = name
|
|
102
|
+
@age = age
|
|
103
|
+
@address = address
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def wurm
|
|
107
|
+
%i[name age address]
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
person = Person.new(
|
|
112
|
+
"Alice",
|
|
113
|
+
30,
|
|
114
|
+
{ city: "Berlin", country: "Germany" }
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
Wurm.pp(person)
|
|
118
|
+
~~~~
|
|
119
|
+
|
|
120
|
+
*Wurm* recursively displays nested structures and their values.
|
|
121
|
+
|
|
122
|
+
Output:
|
|
123
|
+
~~~~ruby
|
|
124
|
+
--- <Person ID: 0x5a8>
|
|
125
|
+
name "Alice"
|
|
126
|
+
age 30
|
|
127
|
+
address <Hash ID: 0x5b0>
|
|
128
|
+
city: "Berlin"
|
|
129
|
+
country: "Germany"
|
|
130
|
+
~~~~
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
## Circular references
|
|
134
|
+
|
|
135
|
+
*Wurm* detects circular references using object identity.
|
|
136
|
+
ruby
|
|
137
|
+
|
|
138
|
+
~~~~ruby
|
|
139
|
+
person = { name: "Alice" }
|
|
140
|
+
person[:friend] = person
|
|
141
|
+
|
|
142
|
+
Wurm.pp(person)
|
|
143
|
+
~~~~
|
|
144
|
+
|
|
145
|
+
Instead of entering an infinite recursion,
|
|
146
|
+
*Wurm* prints a reference to the previously visited object.
|
|
147
|
+
|
|
148
|
+
Output:
|
|
149
|
+
~~~~ruby
|
|
150
|
+
--- <Hash ID: 0x5a8>
|
|
151
|
+
name: "Alice"
|
|
152
|
+
friend: -> reference to --- <Hash ID: 0x5a8>
|
|
153
|
+
~~~~
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
## Shared references
|
|
157
|
+
|
|
158
|
+
*Wurm* also detects objects referenced from multiple locations.
|
|
159
|
+
|
|
160
|
+
~~~~ruby
|
|
161
|
+
shared = { value: 42 }
|
|
162
|
+
|
|
163
|
+
data = {
|
|
164
|
+
first: shared,
|
|
165
|
+
second: shared
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
Wurm.pp(data)
|
|
169
|
+
~~~~
|
|
170
|
+
|
|
171
|
+
The second occurrence is displayed as a reference to the first occurrence.
|
|
172
|
+
|
|
173
|
+
Output:
|
|
174
|
+
~~~~ruby
|
|
175
|
+
--- <Hash ID: 0x5a8>
|
|
176
|
+
first: <Hash ID: 0x5b0>
|
|
177
|
+
value: 42
|
|
178
|
+
second: -> reference to first: <Hash ID: 0x5b0>
|
|
179
|
+
~~~~
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
## Custom output destination
|
|
183
|
+
|
|
184
|
+
By default, output is written to $stdout.
|
|
185
|
+
|
|
186
|
+
You can provide another IO object:
|
|
187
|
+
|
|
188
|
+
~~~~ruby
|
|
189
|
+
require "stringio"
|
|
190
|
+
|
|
191
|
+
output = StringIO.new
|
|
192
|
+
|
|
193
|
+
Wurm.pp({ name: "Alice" }, io: output)
|
|
194
|
+
|
|
195
|
+
puts output.string
|
|
196
|
+
~~~~
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
## Supported types
|
|
200
|
+
|
|
201
|
+
|Ruby type | Handling |
|
|
202
|
+
|---------------|----------|
|
|
203
|
+
|NilClass | Scalar |
|
|
204
|
+
|TrueClass | Scalar |
|
|
205
|
+
|FalseClass | Scalar |
|
|
206
|
+
|Numeric | Scalar |
|
|
207
|
+
|Symbol | Scalar |
|
|
208
|
+
|String | Scalar |
|
|
209
|
+
|Regexp | Scalar |
|
|
210
|
+
|Time | ISO 8601 |
|
|
211
|
+
|Date | ISO 8601 |
|
|
212
|
+
|DateTime | ISO 8601 |
|
|
213
|
+
|Hash | Recursive |
|
|
214
|
+
|Array | Recursive |
|
|
215
|
+
|Struct | Recursive |
|
|
216
|
+
|Custom objects | Via wurm method |
|
|
217
|
+
|
|
218
|
+
## Miscellaneous
|
|
219
|
+
|
|
220
|
+
Copyright (c) 2026 Dittmar Krall (www.matiq.com),
|
|
221
|
+
released under the [MIT license](https://opensource.org/licenses/MIT).
|
data/lib/wurm.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require "wurm2"
|
|
2
|
+
require "date"
|
|
3
|
+
require "time"
|
|
4
|
+
|
|
5
|
+
module Wurm
|
|
6
|
+
INDENT = " "
|
|
7
|
+
|
|
8
|
+
ATOMIC_TYPES = [
|
|
9
|
+
NilClass, TrueClass, FalseClass,
|
|
10
|
+
Numeric, Symbol, String,
|
|
11
|
+
Regexp,
|
|
12
|
+
Time, Date
|
|
13
|
+
].freeze
|
|
14
|
+
|
|
15
|
+
def self.pp(*args, io: $stdout)
|
|
16
|
+
name, object =
|
|
17
|
+
case args.length
|
|
18
|
+
when 1 then ["---", args.first]
|
|
19
|
+
when 2 then args
|
|
20
|
+
else
|
|
21
|
+
raise ArgumentError, "Expected 1 or 2 arguments"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
pp1(name, object, seen: {}.compare_by_identity, io:)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.pp1(name, object, seen:, io:, prefix: "")
|
|
28
|
+
if scalar?(object)
|
|
29
|
+
scalar(name, object, prefix:, io:)
|
|
30
|
+
return
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
if seen.key?(object)
|
|
34
|
+
io.puts "#{prefix}#{name} -> reference to #{seen[object]}"
|
|
35
|
+
return
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
label = label_for(name, object)
|
|
39
|
+
seen[object] = label
|
|
40
|
+
|
|
41
|
+
recursive(name, object, seen:, prefix:, io:)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.scalar?(object)
|
|
45
|
+
ATOMIC_TYPES.any? { |type| type === object }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.label_for(name, object)
|
|
49
|
+
legend =
|
|
50
|
+
if object.is_a?(Class)
|
|
51
|
+
"Class: #{object}"
|
|
52
|
+
else
|
|
53
|
+
object.class.to_s
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
id = "0x#{object.object_id.to_s(16)}"
|
|
57
|
+
|
|
58
|
+
"#{name} <#{legend} ID: #{id}>"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private_class_method :pp1, :scalar?, :label_for
|
|
62
|
+
end
|
data/lib/wurm2.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require "date"
|
|
2
|
+
|
|
3
|
+
module Wurm
|
|
4
|
+
def self.scalar(name, object, prefix:, io:)
|
|
5
|
+
value = case object
|
|
6
|
+
when DateTime, Time, Date then object.iso8601
|
|
7
|
+
else object.inspect
|
|
8
|
+
end
|
|
9
|
+
io.puts "#{prefix}#{name} #{value}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.recursive(name, object, seen:, prefix:, io:)
|
|
13
|
+
io.puts "#{prefix}#{label_for(name, object)}"
|
|
14
|
+
|
|
15
|
+
child_prefix = prefix + INDENT
|
|
16
|
+
|
|
17
|
+
case object
|
|
18
|
+
when Struct
|
|
19
|
+
object.each_pair do |key, value|
|
|
20
|
+
pp1("#{key}:", value, prefix: child_prefix, seen:, io:)
|
|
21
|
+
end
|
|
22
|
+
when Hash
|
|
23
|
+
object.each do |key, value|
|
|
24
|
+
if key.is_a?(Symbol)
|
|
25
|
+
pp1("#{key}:", value, prefix: child_prefix, seen:, io:)
|
|
26
|
+
else
|
|
27
|
+
pp1("#{key.inspect} =>", value, prefix: child_prefix, seen:, io:)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
when Array
|
|
31
|
+
object.each_with_index do |value, index|
|
|
32
|
+
pp1("[#{index}]", value, prefix: child_prefix, seen:, io:)
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
list = object.wurm if object.respond_to?(:wurm)
|
|
36
|
+
list ||= []
|
|
37
|
+
list.each do |attribute|
|
|
38
|
+
value = object.send(attribute)
|
|
39
|
+
pp1(attribute, value, prefix: child_prefix, seen:, io:)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private_class_method :scalar, :recursive
|
|
45
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: wurm
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Dittmar Krall
|
|
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: simplecov
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: standard
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
description: A pretty printer for Ruby objects with circular reference detection.
|
|
41
|
+
email:
|
|
42
|
+
- dittmar.krall@matiq.com
|
|
43
|
+
- dittmar.krall@gmail.com
|
|
44
|
+
executables: []
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- README.md
|
|
49
|
+
- lib/wurm.rb
|
|
50
|
+
- lib/wurm2.rb
|
|
51
|
+
homepage: https://github.com/matique/wurm
|
|
52
|
+
licenses:
|
|
53
|
+
- MIT
|
|
54
|
+
metadata: {}
|
|
55
|
+
rdoc_options: []
|
|
56
|
+
require_paths:
|
|
57
|
+
- lib
|
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '3'
|
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
requirements: []
|
|
69
|
+
rubygems_version: 4.0.23
|
|
70
|
+
specification_version: 4
|
|
71
|
+
summary: A recursive Ruby object pretty printer
|
|
72
|
+
test_files: []
|