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,81 @@
1
+ module Hexdump
2
+ class Theme
3
+ #
4
+ # Represents an ANSI control sequence.
5
+ #
6
+ # @api private
7
+ #
8
+ # @since 1.0.0
9
+ #
10
+ class ANSI
11
+ # ANSI reset control sequence
12
+ RESET = "\e[0m"
13
+
14
+ PARAMETERS = {
15
+ reset: RESET,
16
+
17
+ bold: "\e[1m",
18
+ faint: "\e[2m",
19
+ italic: "\e[3m",
20
+ underline: "\e[4m",
21
+ invert: "\e[7m",
22
+ strike: "\e[9m",
23
+ black: "\e[30m",
24
+ red: "\e[31m",
25
+ green: "\e[32m",
26
+ yellow: "\e[33m",
27
+ blue: "\e[34m",
28
+ magenta: "\e[35m",
29
+ cyan: "\e[36m",
30
+ white: "\e[37m",
31
+
32
+ on_black: "\e[40m",
33
+ on_red: "\e[41m",
34
+ on_green: "\e[42m",
35
+ on_yellow: "\e[43m",
36
+ on_blue: "\e[44m",
37
+ on_magenta: "\e[45m",
38
+ on_cyan: "\e[46m",
39
+ on_white: "\e[47m"
40
+ }
41
+
42
+ # The style name(s).
43
+ #
44
+ # @return [Symbol, Array<Symbol>] style
45
+ attr_reader :parameters
46
+
47
+ # The ANSI string.
48
+ #
49
+ # @return [String]
50
+ attr_reader :string
51
+
52
+ #
53
+ # Initializes an ANSI control sequence.
54
+ #
55
+ # @param [Symbol, Array<Symbol>] style
56
+ #
57
+ def initialize(parameters)
58
+ @parameters = parameters
59
+
60
+ @string = String.new
61
+
62
+ Array(parameters).each do |name|
63
+ @string << PARAMETERS.fetch(name) do
64
+ raise(ArgumentError,"unknown ANSI parameter: #{name}")
65
+ end
66
+ end
67
+ end
68
+
69
+ #
70
+ # Returns the ANSI string.
71
+ #
72
+ # @return [String]
73
+ #
74
+ def to_s
75
+ @string
76
+ end
77
+
78
+ alias to_str to_s
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,159 @@
1
+ require 'hexdump/theme/ansi'
2
+
3
+ require 'strscan'
4
+
5
+ module Hexdump
6
+ class Theme
7
+ #
8
+ # Represents a color highlighting rule.
9
+ #
10
+ # @api private
11
+ #
12
+ # @since 1.0.0
13
+ #
14
+ class Rule
15
+
16
+ # The default style to apply to strings.
17
+ #
18
+ # @return [ANSI, nil]
19
+ attr_reader :style
20
+
21
+ # Highlighting rules for exact strings.
22
+ #
23
+ # @return [Hash{String => ANSI}]
24
+ attr_reader :highlight_strings
25
+
26
+ # Highlighting rules for matching substrings.
27
+ #
28
+ # @return [Hash{String => ANSI}]
29
+ attr_reader :highlight_regexps
30
+
31
+ #
32
+ # Initializes the color.
33
+ #
34
+ # @param [Symbol, Array<Symbol>] style
35
+ # The default style name(s). See {ANSI::PARAMETERS}.
36
+ #
37
+ # @param [Hash{String,Regexp => Symbol,Array<Symbol>}, nil] highlights
38
+ # Optional highlighting rules.
39
+ #
40
+ def initialize(style: nil, highlights: nil)
41
+ @reset = ANSI::RESET
42
+
43
+ @style = if style
44
+ ANSI.new(style)
45
+ end
46
+
47
+ @highlight_strings = {}
48
+ @highlight_regexps = {}
49
+
50
+ if highlights
51
+ highlights.each do |pattern,style|
52
+ highlight(pattern,style)
53
+ end
54
+ end
55
+ end
56
+
57
+ #
58
+ # The highlighting rules.
59
+ #
60
+ # @return [Hash{String,Regexp => ANSI}]
61
+ # The combination of {#highlight_strings} and {#highlight_regexps}.
62
+ #
63
+ def highlights
64
+ @highlight_strings.merge(@highlight_regexps)
65
+ end
66
+
67
+ #
68
+ # Adds a highlighting rule.
69
+ #
70
+ # @param [String, Regexp] pattern
71
+ # The exact String to highlight or regular expression to highlight.
72
+ #
73
+ # @param [Symbol, Array<Symbol>] style
74
+ # The style name(s). See {ANSI::PARAMETERS}.
75
+ #
76
+ # @raise [ArgumentError]
77
+ # The given pattern was not a String or Regexp.
78
+ #
79
+ # @example
80
+ # hexdump.style.numeric.highlight('00', :faint)
81
+ #
82
+ # @example
83
+ # hexdump.style.index.highlight(/00$/, [:white, :bold])
84
+ #
85
+ # @api public
86
+ #
87
+ def highlight(pattern,style)
88
+ ansi = ANSI.new(style)
89
+
90
+ case pattern
91
+ when String
92
+ @highlight_strings[pattern] = ansi
93
+ when Regexp
94
+ @highlight_regexps[pattern] = ansi
95
+ else
96
+ raise(ArgumentError,"pattern must be a String or Regexp: #{pattern.inspect}")
97
+ end
98
+ end
99
+
100
+ #
101
+ # Applies coloring/highlighting to a string.
102
+ #
103
+ # @param [String] string
104
+ # The string to color/highlight.
105
+ #
106
+ # @return [String]
107
+ # The colored the string.
108
+ #
109
+ def apply(string)
110
+ if (!@highlight_strings.empty? || !@highlight_regexps.empty?)
111
+ apply_highlight(string)
112
+ elsif @style
113
+ "#{@style}#{string}#{@reset}"
114
+ else
115
+ string
116
+ end
117
+ end
118
+
119
+ private
120
+
121
+ def apply_highlight(string)
122
+ if (ansi = @highlight_strings[string])
123
+ # highlight the whole string
124
+ "#{ansi}#{string}#{@reset}"
125
+ else
126
+ scanner = StringScanner.new(string)
127
+ new_string = String.new
128
+
129
+ until scanner.eos?
130
+ matched = false
131
+
132
+ @highlight_regexps.each do |regexp,ansi|
133
+ if (match = scanner.scan(regexp))
134
+ # highlight the match
135
+ new_string << "#{ansi}#{match}#{@reset}"
136
+ new_string << "#{@style}" unless scanner.eos?
137
+ matched = true
138
+ break
139
+ end
140
+ end
141
+
142
+ unless matched
143
+ # next char
144
+ new_string << scanner.getch
145
+ end
146
+ end
147
+
148
+ if @style
149
+ new_string.prepend(@style) unless new_string.start_with?("\e")
150
+ new_string << @reset unless new_string.end_with?(@reset)
151
+ end
152
+
153
+ new_string
154
+ end
155
+ end
156
+
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,61 @@
1
+ require 'hexdump/theme/rule'
2
+
3
+ module Hexdump
4
+ #
5
+ # Represents a hexdump theme (styling + highlighting).
6
+ #
7
+ # @api semipublic
8
+ #
9
+ # @since 1.0.0
10
+ #
11
+ class Theme
12
+
13
+ # The index styling/highlights.
14
+ #
15
+ # @return [Rule, nil]
16
+ #
17
+ # @api public
18
+ attr_reader :index
19
+
20
+ # The numeric styling/highlights.
21
+ #
22
+ # @return [Rule, nil]
23
+ #
24
+ # @api public
25
+ attr_reader :numeric
26
+
27
+ # The chars styling/highlights.
28
+ #
29
+ # @return [Rule, nil]
30
+ #
31
+ # @api public
32
+ attr_reader :chars
33
+
34
+ #
35
+ # Initializes the theme.
36
+ #
37
+ # @param [Hash{:index,:numeric,:chars => Symbol,Array<Symbol>,nil}] style
38
+ # The default style of the index, numeric, and/or chars columns.
39
+ #
40
+ # @param [Hash{:index,:numeric,:chars => Hash{String,Regexp => Symbol,Array<Symbol>},nil}] highlights
41
+ # The highlighting rules for the index, numeric, and/or chars columns.
42
+ #
43
+ def initialize(style: {}, highlights: {})
44
+ @index = Rule.new(
45
+ style: style[:index],
46
+ highlights: highlights[:index]
47
+ )
48
+
49
+ @numeric = Rule.new(
50
+ style: style[:numeric],
51
+ highlights: highlights[:numeric]
52
+ )
53
+
54
+ @chars = Rule.new(
55
+ style: style[:chars],
56
+ highlights: highlights[:chars]
57
+ )
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,232 @@
1
+ module Hexdump
2
+ #
3
+ # @api private
4
+ #
5
+ # @since 1.0.0
6
+ #
7
+ class Type
8
+
9
+ # The endian-ness of the type.
10
+ #
11
+ # @return [:little, :big, nil]
12
+ attr_reader :endian
13
+
14
+ # The size in bytes of the type.
15
+ #
16
+ # @return [1, 2, 4, 8]
17
+ attr_reader :size
18
+
19
+ #
20
+ # Initializes the type.
21
+ #
22
+ # @param [Symbol] name
23
+ #
24
+ # @param [:little, :big, nil] endian
25
+ #
26
+ # @param [1, 2, 4, 8] size
27
+ #
28
+ # @param [Boolean] signed
29
+ #
30
+ # @raise [ArgumentError]
31
+ # Invalid `endian:` or `size:` values.
32
+ #
33
+ def initialize(size: , endian: nil, signed: )
34
+ @endian = endian
35
+ @size = size
36
+ @signed = signed
37
+ end
38
+
39
+ #
40
+ # Whether the type is signed.
41
+ #
42
+ # @return [Boolean]
43
+ #
44
+ def signed?
45
+ @signed
46
+ end
47
+
48
+ #
49
+ # Whether the type is unsigned.
50
+ #
51
+ # @return [Boolean]
52
+ #
53
+ def unsigned?
54
+ !@signed
55
+ end
56
+
57
+ # The native endian-ness.
58
+ NATIVE_ENDIAN = if [0x1].pack('I') == [0x1].pack('N')
59
+ :big
60
+ else
61
+ :little
62
+ end
63
+
64
+ #
65
+ # Represents a signed integer type.
66
+ #
67
+ class Int < self
68
+
69
+ #
70
+ # Initializes the int type.
71
+ #
72
+ # @param [:little, :big] endian (NATIVE_ENDIAN)
73
+ # The endian-ness of the int type.
74
+ #
75
+ def initialize(endian: NATIVE_ENDIAN, **kwargs)
76
+ super(signed: true, endian: endian, **kwargs)
77
+ end
78
+
79
+ end
80
+
81
+ class Int8 < Int
82
+
83
+ #
84
+ # @see Int#initialize
85
+ #
86
+ def initialize(**kwargs)
87
+ super(size: 1, endian: nil, **kwargs)
88
+ end
89
+
90
+ end
91
+
92
+ class Int16 < Int
93
+
94
+ #
95
+ # @see Int#initialize
96
+ #
97
+ def initialize(**kwargs)
98
+ super(size: 2, **kwargs)
99
+ end
100
+
101
+ end
102
+
103
+ class Int32 < Int
104
+
105
+ #
106
+ # @see Int#initialize
107
+ #
108
+ def initialize(**kwargs)
109
+ super(size: 4, **kwargs)
110
+ end
111
+
112
+ end
113
+
114
+ class Int64 < Int
115
+
116
+ #
117
+ # @see Int#initialize
118
+ #
119
+ def initialize(**kwargs)
120
+ super(size: 8, **kwargs)
121
+ end
122
+
123
+ end
124
+
125
+ #
126
+ # Represents a unsigned integer type.
127
+ #
128
+ class UInt < self
129
+
130
+ #
131
+ # Initializes the uint type.
132
+ #
133
+ # @param [:little, :big] endian (NATIVE_ENDIAN)
134
+ # The endian-ness of the uint type.
135
+ #
136
+ def initialize(endian: NATIVE_ENDIAN, **kwargs)
137
+ super(signed: false, endian: endian, **kwargs)
138
+ end
139
+
140
+ end
141
+
142
+ class UInt8 < UInt
143
+
144
+ #
145
+ # @see UInt#initialize
146
+ #
147
+ def initialize(**kwargs)
148
+ super(size: 1, endian: nil, **kwargs)
149
+ end
150
+
151
+ end
152
+
153
+ class UInt16 < UInt
154
+
155
+ #
156
+ # @see UInt#initialize
157
+ #
158
+ def initialize(**kwargs)
159
+ super(size: 2, **kwargs)
160
+ end
161
+
162
+ end
163
+
164
+ class UInt32 < UInt
165
+
166
+ #
167
+ # @see UInt#initialize
168
+ #
169
+ def initialize(**kwargs)
170
+ super(size: 4, **kwargs)
171
+ end
172
+
173
+ end
174
+
175
+ class UInt64 < UInt
176
+
177
+ #
178
+ # @see UInt#initialize
179
+ #
180
+ def initialize(**kwargs)
181
+ super(size: 8, **kwargs)
182
+ end
183
+
184
+ end
185
+
186
+ #
187
+ # Represents a single-byte character.
188
+ #
189
+ class Char < Int8
190
+ end
191
+
192
+ #
193
+ # Represents a single-byte unsigned character.
194
+ #
195
+ class UChar < UInt8
196
+ end
197
+
198
+ #
199
+ # Represents a floating point type.
200
+ #
201
+ class Float < self
202
+
203
+ #
204
+ # Initializes the float type.
205
+ #
206
+ # @param [:little, :big] endian (NATIVE_ENDIAN)
207
+ # The endian-ness of the float type.
208
+ #
209
+ def initialize(endian: NATIVE_ENDIAN, **kwargs)
210
+ super(signed: true, endian: endian, **kwargs)
211
+ end
212
+
213
+ end
214
+
215
+ class Float32 < Float
216
+
217
+ def initialize(**kwargs)
218
+ super(size: 4, **kwargs)
219
+ end
220
+
221
+ end
222
+
223
+ class Float64 < Float
224
+
225
+ def initialize(**kwargs)
226
+ super(size: 8, **kwargs)
227
+ end
228
+
229
+ end
230
+
231
+ end
232
+ end