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.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +221 -0
  3. data/lib/wurm.rb +62 -0
  4. data/lib/wurm2.rb +45 -0
  5. 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
+ [![Gem Version](https://img.shields.io/gem/v/wurm?color=168AFE&logo=rubygems&logoColor=FE1616)](https://rubygems.org/gems/wurm)
4
+ [![Downloads](https://img.shields.io/gem/dt/wurm?color=168AFE&logo=rubygems&logoColor=FE1616)](https://rubygems.org/gems/wurm)
5
+ [![GitHub Build](https://img.shields.io/github/actions/workflow/status/matique/wurm/rake.yml?logo=github)](https://github.com/matique/wurm/actions/workflows/rake.yml)
6
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-168AFE.svg)](https://github.com/standardrb/standard)
7
+ [![MIT License](https://img.shields.io/badge/license-MIT-168AFE.svg)](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: []