hexdump 0.3.0 → 1.0.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +68 -2
  3. data/Gemfile +1 -0
  4. data/README.md +486 -135
  5. data/benchmark.rb +29 -22
  6. data/lib/hexdump/chars.rb +46 -0
  7. data/lib/hexdump/core_ext/file.rb +68 -6
  8. data/lib/hexdump/core_ext/io.rb +2 -2
  9. data/lib/hexdump/core_ext/kernel.rb +7 -0
  10. data/lib/hexdump/core_ext/string.rb +2 -2
  11. data/lib/hexdump/core_ext/string_io.rb +2 -2
  12. data/lib/hexdump/core_ext.rb +1 -0
  13. data/lib/hexdump/format_string.rb +43 -0
  14. data/lib/hexdump/hexdump.rb +768 -75
  15. data/lib/hexdump/mixin.rb +198 -0
  16. data/lib/hexdump/module_methods.rb +132 -0
  17. data/lib/hexdump/numeric/binary.rb +55 -0
  18. data/lib/hexdump/numeric/char_or_int.rb +90 -0
  19. data/lib/hexdump/numeric/decimal.rb +56 -0
  20. data/lib/hexdump/numeric/exceptions.rb +11 -0
  21. data/lib/hexdump/numeric/hexadecimal.rb +59 -0
  22. data/lib/hexdump/numeric/octal.rb +55 -0
  23. data/lib/hexdump/numeric.rb +5 -0
  24. data/lib/hexdump/reader.rb +314 -0
  25. data/lib/hexdump/theme/ansi.rb +81 -0
  26. data/lib/hexdump/theme/rule.rb +159 -0
  27. data/lib/hexdump/theme.rb +61 -0
  28. data/lib/hexdump/type.rb +232 -0
  29. data/lib/hexdump/types.rb +108 -0
  30. data/lib/hexdump/version.rb +1 -1
  31. data/lib/hexdump.rb +12 -1
  32. data/spec/chars_spec.rb +76 -0
  33. data/spec/core_ext_spec.rb +10 -6
  34. data/spec/hexdump_class_spec.rb +1708 -0
  35. data/spec/hexdump_module_spec.rb +23 -0
  36. data/spec/mixin_spec.rb +37 -0
  37. data/spec/numeric/binary_spec.rb +239 -0
  38. data/spec/numeric/char_or_int_spec.rb +210 -0
  39. data/spec/numeric/decimal_spec.rb +317 -0
  40. data/spec/numeric/hexadecimal_spec.rb +320 -0
  41. data/spec/numeric/octal_spec.rb +239 -0
  42. data/spec/reader_spec.rb +863 -0
  43. data/spec/theme/ansi_spec.rb +242 -0
  44. data/spec/theme/rule_spec.rb +199 -0
  45. data/spec/theme_spec.rb +94 -0
  46. data/spec/type_spec.rb +317 -0
  47. data/spec/types_spec.rb +904 -0
  48. metadata +39 -10
  49. data/.gemtest +0 -0
  50. data/lib/hexdump/dumper.rb +0 -419
  51. data/spec/dumper_spec.rb +0 -329
  52. data/spec/hexdump_spec.rb +0 -30
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+ require 'hexdump'
3
+
4
+ describe Hexdump do
5
+ let(:data) { ("A" * 32) + ("B" * 32) + ("C" * 32) }
6
+ let(:hexdump) { Hexdump::Hexdump.new.dump(data) }
7
+
8
+ describe ".hexdump" do
9
+ it "must write the hexdump lines of the given data to the output" do
10
+ expect {
11
+ subject.hexdump(data)
12
+ }.to output(hexdump).to_stdout
13
+ end
14
+ end
15
+
16
+ describe ".dump" do
17
+ it "must write the hexdump lines of the given data to the output" do
18
+ expect {
19
+ subject.dump(data)
20
+ }.to output(hexdump).to_stdout
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'hexdump/mixin'
3
+
4
+ describe Hexdump::Mixin do
5
+ class TestMixin
6
+
7
+ include Hexdump::Mixin
8
+
9
+ def initialize(data)
10
+ @data = data
11
+ end
12
+
13
+ def each_byte(&block)
14
+ @data.each_byte(&block)
15
+ end
16
+
17
+ end
18
+
19
+ let(:data) { ("A" * 32) + ("B" * 32) + ("C" * 32) }
20
+ let(:hexdump) { Hexdump::Hexdump.new.dump(data) }
21
+
22
+ subject { TestMixin.new(data) }
23
+
24
+ describe "#hexdump" do
25
+ it "must write the hexdump lines of the object to $stdout" do
26
+ expect {
27
+ subject.hexdump
28
+ }.to output(hexdump).to_stdout
29
+ end
30
+ end
31
+
32
+ describe "#to_hexdump" do
33
+ it "must return the hexdump lines of the object" do
34
+ expect(subject.to_hexdump).to eq(hexdump)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,239 @@
1
+ require 'spec_helper'
2
+ require 'hexdump/numeric/binary'
3
+ require 'hexdump/type'
4
+
5
+ describe Hexdump::Numeric::Binary do
6
+ describe "#initialize" do
7
+ subject { described_class.new(type) }
8
+
9
+ context "when given a Type::Int type" do
10
+ context "and size is 1" do
11
+ let(:type) { Hexdump::Type::Int8.new }
12
+
13
+ it "must set #width to 8 + 1" do
14
+ expect(subject.width).to eq(8 + 1)
15
+ end
16
+ end
17
+
18
+ context "and size is 2" do
19
+ let(:type) { Hexdump::Type::Int16.new }
20
+
21
+ it "must set #width to 16 + 1" do
22
+ expect(subject.width).to eq(16 + 1)
23
+ end
24
+ end
25
+
26
+ context "and size is 4" do
27
+ let(:type) { Hexdump::Type::Int32.new }
28
+
29
+ it "must set #width to 32 + 1" do
30
+ expect(subject.width).to eq(32 + 1)
31
+ end
32
+ end
33
+
34
+ context "and size is 8" do
35
+ let(:type) { Hexdump::Type::Int64.new }
36
+
37
+ it "must set #width to 64 + 1" do
38
+ expect(subject.width).to eq(64 + 1)
39
+ end
40
+ end
41
+
42
+ context "but the type has an unsupported size" do
43
+ class UnsupportedIntType < Hexdump::Type::Int
44
+
45
+ def initialize
46
+ super(size: 3)
47
+ end
48
+
49
+ end
50
+
51
+ let(:type) { UnsupportedIntType.new }
52
+
53
+ it do
54
+ expect { described_class.new(type) }.to raise_error(NotImplementedError)
55
+ end
56
+ end
57
+ end
58
+
59
+ context "when given a Type::UInt type" do
60
+ context "and size is 1" do
61
+ let(:type) { Hexdump::Type::UInt8.new }
62
+
63
+ it "must set #width to 8" do
64
+ expect(subject.width).to eq(8)
65
+ end
66
+ end
67
+
68
+ context "and size is 2" do
69
+ let(:type) { Hexdump::Type::UInt16.new }
70
+
71
+ it "must set #width to 16" do
72
+ expect(subject.width).to eq(16)
73
+ end
74
+ end
75
+
76
+ context "and size is 4" do
77
+ let(:type) { Hexdump::Type::UInt32.new }
78
+
79
+ it "must set #width to 32" do
80
+ expect(subject.width).to eq(32)
81
+ end
82
+ end
83
+
84
+ context "and size is 8" do
85
+ let(:type) { Hexdump::Type::UInt64.new }
86
+
87
+ it "must set #width to 64" do
88
+ expect(subject.width).to eq(64)
89
+ end
90
+ end
91
+
92
+ context "but the type has an unsupported size" do
93
+ class UnsupportedUIntType < Hexdump::Type::UInt
94
+
95
+ def initialize
96
+ super(size: 3)
97
+ end
98
+
99
+ end
100
+
101
+ let(:type) { UnsupportedUIntType.new }
102
+
103
+ it do
104
+ expect { described_class.new(type) }.to raise_error(NotImplementedError)
105
+ end
106
+ end
107
+ end
108
+
109
+ context "when given a Type::Float type" do
110
+ let(:type) { Hexdump::Type::Float32.new }
111
+
112
+ it do
113
+ expect {
114
+ described_class.new(type)
115
+ }.to raise_error(Hexdump::Numeric::IncompatibleTypeError,"cannot format floating-point numbers in binary")
116
+ end
117
+ end
118
+
119
+ context "when given a non-Type object" do
120
+ let(:type) { Object.new }
121
+
122
+ it do
123
+ expect { described_class.new(type) }.to raise_error(TypeError)
124
+ end
125
+ end
126
+ end
127
+
128
+ describe "#%" do
129
+ subject { described_class.new(type) }
130
+
131
+ context "when the given type has size 1" do
132
+ let(:type) { Hexdump::Type::UInt8.new }
133
+
134
+ let(:value) { 0xf }
135
+ let(:binary) { '00001111' }
136
+
137
+ it "must return a binary string of length 8" do
138
+ expect(subject % value).to eq(binary)
139
+ end
140
+
141
+ context "and is signed" do
142
+ let(:type) { Hexdump::Type::Int8.new }
143
+
144
+ context "and the value is positive" do
145
+ it "must return a binary string of length 8 prefixed with a ' '" do
146
+ expect(subject % value).to eq(" #{binary}")
147
+ end
148
+ end
149
+
150
+ context "and the value is negative" do
151
+ it "must return a binary string of length 8 prefixed with a '-'" do
152
+ expect(subject % -value).to eq("-#{binary}")
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ context "when the given type has size 2" do
159
+ let(:type) { Hexdump::Type::UInt16.new }
160
+
161
+ let(:value) { 0xff }
162
+ let(:binary) { '0000000011111111' }
163
+
164
+ it "must return a binary string of length 16" do
165
+ expect(subject % value).to eq(binary)
166
+ end
167
+
168
+ context "and is signed" do
169
+ let(:type) { Hexdump::Type::Int16.new }
170
+
171
+ context "and the value is positive" do
172
+ it "must return a binary string of length 16 prefixed with a ' '" do
173
+ expect(subject % value).to eq(" #{binary}")
174
+ end
175
+ end
176
+
177
+ context "and the value is negative" do
178
+ it "must return a binary string of length 16 prefixed with a '-'" do
179
+ expect(subject % -value).to eq("-#{binary}")
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+ context "when the given type has size 4" do
186
+ let(:type) { Hexdump::Type::UInt32.new }
187
+
188
+ let(:value) { 0xffff }
189
+ let(:binary) { '00000000000000001111111111111111' }
190
+
191
+ it "must return a binary string of length 32" do
192
+ expect(subject % value).to eq(binary)
193
+ end
194
+
195
+ context "and is signed" do
196
+ let(:type) { Hexdump::Type::Int32.new }
197
+
198
+ context "and the value is positive" do
199
+ it "must return a binary string of length 32 prefixed with a ' '" do
200
+ expect(subject % value).to eq(" #{binary}")
201
+ end
202
+ end
203
+
204
+ context "and the value is negative" do
205
+ it "must return a binary string of length 32 prefixed with a '-'" do
206
+ expect(subject % -value).to eq("-#{binary}")
207
+ end
208
+ end
209
+ end
210
+ end
211
+
212
+ context "when the given type has size 8" do
213
+ let(:type) { Hexdump::Type::UInt64.new }
214
+
215
+ let(:value) { 0xffffffff }
216
+ let(:binary) { '0000000000000000000000000000000011111111111111111111111111111111' }
217
+
218
+ it "must return a binary string of length 64" do
219
+ expect(subject % value).to eq(binary)
220
+ end
221
+
222
+ context "and is signed" do
223
+ let(:type) { Hexdump::Type::Int64.new }
224
+
225
+ context "and the value is positive" do
226
+ it "must return a binary string of length 64 prefixed with a ' '" do
227
+ expect(subject % value).to eq(" #{binary}")
228
+ end
229
+ end
230
+
231
+ context "and the value is negative" do
232
+ it "must return a binary string of length 64 prefixed with a '-'" do
233
+ expect(subject % -value).to eq("-#{binary}")
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,210 @@
1
+ require 'spec_helper'
2
+ require 'hexdump/numeric/char_or_int'
3
+ require 'hexdump/numeric/hexadecimal'
4
+ require 'hexdump/type'
5
+
6
+ describe Hexdump::Numeric::CharOrInt do
7
+ let(:type) { Hexdump::Type::UInt8.new }
8
+ let(:base) { Hexdump::Numeric::Hexadecimal.new(type) }
9
+
10
+ subject { described_class.new(base) }
11
+
12
+ describe "#initialize" do
13
+ it "must set #base" do
14
+ expect(subject.base).to eq(base)
15
+ end
16
+
17
+ it "must default #encoding to nil" do
18
+ expect(subject.encoding).to be(nil)
19
+ end
20
+
21
+ it "must initialize the format string" do
22
+ expect(subject.to_s).to eq("%#{base.width}s")
23
+ end
24
+
25
+ context "when given an encoding" do
26
+ let(:encoding) { Encoding::UTF_8 }
27
+
28
+ subject { described_class.new(base,encoding) }
29
+
30
+ it "must set #encoding" do
31
+ expect(subject.encoding).to eq(encoding)
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#width" do
37
+ it "return the base's #width" do
38
+ expect(subject.width).to eq(base.width)
39
+ end
40
+ end
41
+
42
+ describe "#%" do
43
+ (0x20..0x7e).each do |byte|
44
+ context "when given #{byte.to_s(16)}" do
45
+ it "must return ' #{byte.chr}'" do
46
+ expect(subject % byte).to eq(" #{byte.chr}")
47
+ end
48
+ end
49
+ end
50
+
51
+ context "when given 0x00" do
52
+ it "must return '\\0'" do
53
+ expect(subject % 0x00).to eq("\\0")
54
+ end
55
+ end
56
+
57
+ context "when given 0x07" do
58
+ it "must return '\\a'" do
59
+ expect(subject % 0x07).to eq("\\a")
60
+ end
61
+ end
62
+
63
+ context "when given 0x08" do
64
+ it "must return '\\b'" do
65
+ expect(subject % 0x08).to eq("\\b")
66
+ end
67
+ end
68
+
69
+ context "when given 0x09" do
70
+ it "must return '\\t'" do
71
+ expect(subject % 0x09).to eq("\\t")
72
+ end
73
+ end
74
+
75
+ context "when given 0x0a" do
76
+ it "must return '\\n'" do
77
+ expect(subject % 0x0a).to eq("\\n")
78
+ end
79
+ end
80
+
81
+ context "when given 0x0b" do
82
+ it "must return '\\v'" do
83
+ expect(subject % 0x0b).to eq("\\v")
84
+ end
85
+ end
86
+
87
+ context "when given 0x0c" do
88
+ it "must return '\\f'" do
89
+ expect(subject % 0x0c).to eq("\\f")
90
+ end
91
+ end
92
+
93
+ context "when given 0x0d" do
94
+ it "must return '\\r'" do
95
+ expect(subject % 0x0d).to eq("\\r")
96
+ end
97
+ end
98
+
99
+ context "when given a byte that does not map to a printable character" do
100
+ it "must return the formatted byte" do
101
+ expect(subject % 0xff).to eq("ff")
102
+ end
103
+ end
104
+
105
+ context "when the numeric base has a width > 2" do
106
+ let(:type) { Hexdump::Type::UInt16.new }
107
+ let(:width) { base.width }
108
+
109
+ it "must left-pad printable characters with width-1 additional spaces" do
110
+ left_pad = ' ' * (width - 1)
111
+
112
+ expect(subject % 0x41).to eq("#{left_pad}A")
113
+ end
114
+
115
+ it "must left-pad escaped characters with width-2 additional spaces" do
116
+ left_pad = ' ' * (width - 2)
117
+
118
+ expect(subject % 0x00).to eq("#{left_pad}\\0")
119
+ end
120
+
121
+ it "must not left-pad numerically formatted values with spaces" do
122
+ expect(subject % 0xff).to eq("00ff")
123
+ end
124
+ end
125
+
126
+ context "when initialized with an encoding" do
127
+ let(:encoding) { Encoding::UTF_8 }
128
+
129
+ subject { described_class.new(base,encoding) }
130
+
131
+ context "when given 0x00" do
132
+ it "must return '\\0'" do
133
+ expect(subject % 0x00).to eq("\\0")
134
+ end
135
+ end
136
+
137
+ context "when given 0x07" do
138
+ it "must return '\\a'" do
139
+ expect(subject % 0x07).to eq("\\a")
140
+ end
141
+ end
142
+
143
+ context "when given 0x08" do
144
+ it "must return '\\b'" do
145
+ expect(subject % 0x08).to eq("\\b")
146
+ end
147
+ end
148
+
149
+ context "when given 0x09" do
150
+ it "must return '\\t'" do
151
+ expect(subject % 0x09).to eq("\\t")
152
+ end
153
+ end
154
+
155
+ context "when given 0x0a" do
156
+ it "must return '\\n'" do
157
+ expect(subject % 0x0a).to eq("\\n")
158
+ end
159
+ end
160
+
161
+ context "when given 0x0b" do
162
+ it "must return '\\v'" do
163
+ expect(subject % 0x0b).to eq("\\v")
164
+ end
165
+ end
166
+
167
+ context "when given 0x0c" do
168
+ it "must return '\\f'" do
169
+ expect(subject % 0x0c).to eq("\\f")
170
+ end
171
+ end
172
+
173
+ context "when given 0x0d" do
174
+ it "must return '\\r'" do
175
+ expect(subject % 0x0d).to eq("\\r")
176
+ end
177
+ end
178
+
179
+ context "when given a byte that does map to a printable character" do
180
+ it "must return the formatted character" do
181
+ expect(subject % 0x2603).to eq(" ☃")
182
+ end
183
+ end
184
+
185
+ context "when given a byte that does not map to a printable character" do
186
+ let(:byte) { 888 }
187
+
188
+ it "must return the numeric formatted value" do
189
+ expect(subject % byte).to eq(base % byte)
190
+ end
191
+ end
192
+
193
+ context "when given a byte that does not map any character" do
194
+ let(:byte) { 0xd800 }
195
+
196
+ it "must return the numeric formatted value" do
197
+ expect(subject % byte).to eq(base % byte)
198
+ end
199
+ end
200
+
201
+ context "when given a negative value" do
202
+ let(:byte) { -1 }
203
+
204
+ it "must return the numeric formatted value" do
205
+ expect(subject % byte).to eq(base % byte)
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end