xprint 0.9.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 (4) hide show
  1. checksums.yaml +7 -0
  2. data/lib/version.rb +3 -0
  3. data/lib/xprint.rb +363 -0
  4. metadata +47 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 72c5d81ad083539ab972c38b51405d5275034ce535f4014696257dbec0d6e5ab
4
+ data.tar.gz: 950f5d948e5098902d02d25eea8a62c1ec146a0dd58bb052bed139df50d06512
5
+ SHA512:
6
+ metadata.gz: 33fb5f501119a0cb8015797c93f72516276eb332a03b9dba5f01696965a2ab2b8d06659724c8e12dcb3c9dd287df0311a6a11b48e9bef51fdf5bc329e9d114b5
7
+ data.tar.gz: 11492f4674dcd327edf54cfe909c1c830236ce798f34c830a8ac5f74b36e860ea3548d44af465a72a5ca73af90c8ff5ce3d92f8f8fc429baff92e8d0c2bafaa4
@@ -0,0 +1,3 @@
1
+ module XPrint
2
+ VERSION = '0.9.1'
3
+ end
@@ -0,0 +1,363 @@
1
+ require 'bigdecimal'
2
+ require 'date'
3
+ require 'yaml'
4
+
5
+ module XPrint
6
+ @data_classes = [
7
+ String, Integer, Float, TrueClass, FalseClass, NilClass,
8
+ Symbol, Date, Time, DateTime, BigDecimal, Rational
9
+ ]
10
+ @hash_name_classes = @data_classes + [Proc]
11
+ @tab = " "
12
+ @indexes = true
13
+ @full_proc_path = false
14
+ @braces = true
15
+ @date_format = '%F'
16
+ @time_format = '%c'
17
+ @datetime_format = '%FT%T%:z'
18
+ @color = true
19
+ @colors = {
20
+ attribute: :blue,
21
+ bigdecimal: :darkcyan,
22
+ classname: :darkgreen,
23
+ classobject: :green,
24
+ date: :red,
25
+ datetime: :purple,
26
+ false: :darkred,
27
+ float: :cyan,
28
+ index: :darkgrey,
29
+ integer: :cyan,
30
+ module: :green,
31
+ nil: :darkpurple,
32
+ proc: :darkyellow,
33
+ rational: :darkcyan,
34
+ string: :yellow,
35
+ struct: :green,
36
+ symbol: :darkblue,
37
+ time: :darkblue,
38
+ true: :darkgreen
39
+ }
40
+ @color_codes = {
41
+ black: "\e[30m",
42
+ blue: "\e[94m",
43
+ darkblue: "\e[34m",
44
+ cyan: "\e[96m",
45
+ darkcyan: "\e[36m",
46
+ green: "\e[92m",
47
+ darkgreen: "\e[32m",
48
+ grey: "\e[37m",
49
+ darkgrey: "\e[90m",
50
+ red: "\e[91m",
51
+ darkred: "\e[31m",
52
+ purple: "\e[95m",
53
+ darkpurple: "\e[35m",
54
+ yellow: "\e[93m",
55
+ darkyellow: "\e[33m",
56
+ reset: "\e[0m"
57
+ }
58
+
59
+ def self.set(**kwargs)
60
+ set_vars = {
61
+ tab: ->(data) { @tab = data },
62
+ indexes: ->(data) { @indexes = data },
63
+ full_proc_path: ->(data) { @full_proc_path = data },
64
+ braces: ->(data) { @braces = data },
65
+ date_format: ->(data) { @date_format = data },
66
+ time_format: ->(data) { @time_format = data },
67
+ datetime_format: ->(data) { @datetime_format = data },
68
+ color: ->(data) { @color = data }
69
+ }
70
+
71
+ kwargs.each do |keyword, arg|
72
+ if set_vars.key? keyword
73
+ set_vars[keyword].(arg)
74
+ end
75
+ end
76
+
77
+ return
78
+ end
79
+
80
+ def self.load_file(config)
81
+ config_data = YAML.load( File.read config )
82
+ config_data = self.symbolize_keys(config_data)
83
+
84
+ if config_data.key? :general
85
+ self.set **config_data[:general]
86
+ end
87
+
88
+ if config_data.key? :colors
89
+ color_data = config_data[:colors]
90
+
91
+ color_data.each do |name, color|
92
+ color_data[name] = color.to_sym
93
+ end
94
+
95
+ self.set_color_for **config_data[:colors]
96
+ end
97
+
98
+ if config_data.key? :'color codes'
99
+ self.set_color_code_for **config_data[:'color codes']
100
+ end
101
+ end
102
+
103
+ def self.load(config)
104
+ calling_file = caller_locations.first.absolute_path
105
+ base_dir = File.dirname calling_file
106
+ relative_config = File.expand_path config, base_dir
107
+
108
+ self.load_file relative_config
109
+ end
110
+
111
+ private_class_method def self.symbolize_keys(hash)
112
+ hash.inject({}) do |result, (key, value)|
113
+ new_key = key.to_sym
114
+ new_value = value.is_a?(Hash) ? symbolize_keys(value) : value
115
+
116
+ result[new_key] = new_value
117
+
118
+ result
119
+ end
120
+ end
121
+
122
+ def self.set_color_for(**kwargs)
123
+ kwargs.each do |keyword, arg|
124
+ @colors[keyword] = arg
125
+ end
126
+ end
127
+
128
+ def self.set_color_code_for(**kwargs)
129
+ kwargs.each do |keyword, arg|
130
+ @color_codes[keyword] = arg
131
+ end
132
+ end
133
+
134
+ def self.xp(*args)
135
+ args.each do |arg|
136
+ xpanded_text = self.xpand(arg, tab: @tab)
137
+
138
+ unless @braces
139
+ xpanded_text = self.shift_indentation_down(xpanded_text).lstrip()
140
+ end
141
+
142
+ puts xpanded_text
143
+ end
144
+ end
145
+
146
+ private_class_method def self.color_for(colorname)
147
+ @color_codes[colorname]
148
+ end
149
+
150
+ private_class_method def self.reset_color()
151
+ @color_codes[:reset]
152
+ end
153
+
154
+ private_class_method def self.colorize(text, type)
155
+ if @color
156
+ item_color = color_for @colors[type]
157
+ "#{item_color}#{text}#{reset_color}"
158
+ else
159
+ text
160
+ end
161
+ end
162
+
163
+ private_class_method def self.shift_indentation_down(text)
164
+ # Only shift if no
165
+ return text if text.match?(/^\S/)
166
+ result = ''
167
+
168
+ text.each_line do |line|
169
+ result += (
170
+ if line.start_with? @tab
171
+ line[@tab.length..-1]
172
+ else
173
+ line
174
+ end
175
+ )
176
+ end
177
+
178
+ return result
179
+ end
180
+
181
+ def self.xpand(x, indent: '', tab: ' ')
182
+
183
+ _indent = "#{tab}#{indent}"
184
+
185
+ # X is a "primitive" kind of data that has no subitems, so
186
+ # we can just print it.
187
+ if x.class == String
188
+ return colorize(x.inspect, :string)
189
+ elsif x.class == Integer
190
+ return colorize(x.inspect, :integer)
191
+ elsif x.class == Float
192
+ return colorize(x.inspect, :float)
193
+ elsif x.class == TrueClass
194
+ return colorize(x.inspect, :true)
195
+ elsif x.class == FalseClass
196
+ return colorize(x.inspect, :false)
197
+ elsif x.class == NilClass
198
+ return colorize(x.inspect, :nil)
199
+ elsif x.class == Symbol
200
+ return colorize(x.inspect, :symbol)
201
+
202
+ # X is a Proc, print more compact version of standard Proc.inspect
203
+ # text.
204
+ elsif x.class == Proc
205
+ type = x.lambda? ? 'Lambda' : 'Proc'
206
+ source, line = x.source_location
207
+ source = source.gsub('\\', '/')
208
+
209
+ unless @full_proc_path
210
+ source = source.split('/')[-2..-1].join('/')
211
+ end
212
+
213
+ return colorize("<#{type} @ #{source} [Line #{line}]>", :proc)
214
+
215
+ elsif x.class == Class
216
+ return colorize("<Class #{x}>", :classobject)
217
+
218
+ # X is an Array, print list of all items.
219
+ elsif x.class == Array
220
+ result = "#{@braces ? '[' : ''}\n"
221
+
222
+ x.each_with_index do |item, index|
223
+ data = xpand(item, indent: _indent, tab: tab)
224
+
225
+ result += "#{_indent}"
226
+ if @indexes
227
+ adjustment = x.length.to_s.length + 3
228
+ # Account for characters used for color coding.
229
+ adjustment += 9 if @color
230
+
231
+ result += "#{colorize("[#{index}]", :index)} ".
232
+ ljust(adjustment)
233
+ end
234
+ result += "#{data}"
235
+
236
+ unless index + 1 == x.length
237
+ result += "#{@braces ? ', ' : ''} \n"
238
+ end
239
+ end
240
+
241
+ result += "\n#{indent}]" if @braces
242
+ return result
243
+
244
+ # X is a Hash, print all keys and values.
245
+ elsif x.class == Hash
246
+ result = "#{@braces ? '{' : ''}\n"
247
+
248
+ longest_key = (
249
+ x.keys.filter do |k, v|
250
+ @hash_name_classes.include? k.class
251
+ end.
252
+ map do |k, v|
253
+ k.to_s.length
254
+ end.
255
+ max()
256
+ )
257
+
258
+ longest_key = 0 if longest_key.nil?
259
+
260
+ # Color codes throw the text length, so we need to add the
261
+ # length of the color code and the code to reset the color
262
+ # that wrap around the colored word.
263
+ # The color code is like "\e[99m" and the reset "\e[0m",
264
+ # so the total length to add when using color is 9.
265
+ longest_key += 9 if @color
266
+
267
+ x.each_with_index do |(key, value), index|
268
+ data_key = "#{xpand(key, indent: _indent, tab: tab)}"
269
+
270
+ data_key = (
271
+ if @hash_name_classes.include? key.class
272
+ data_key.ljust(longest_key + 1)
273
+ else
274
+ data_key.ljust(data_key.length + longest_key)
275
+ end
276
+ )
277
+
278
+ data_value = xpand(value, indent: _indent, tab: tab)
279
+
280
+ result += "#{_indent}#{data_key} => #{data_value}"
281
+
282
+ unless index + 1 == x.length
283
+ result += "#{@braces ? ', ' : ''} \n"
284
+ end
285
+ end
286
+
287
+ result += "\n#{indent}}" if @braces
288
+
289
+ return result
290
+
291
+ # X is a commonly used special kind of object.
292
+ elsif x.class == DateTime
293
+ datetime = x.strftime @datetime_format
294
+ return colorize("DateTime(#{datetime})", :datetime)
295
+
296
+ elsif x.class == Date
297
+ date = x.strftime @date_format
298
+ return colorize("Date(#{date})", :date)
299
+
300
+ elsif x.class == Time
301
+ time = x.strftime @time_format
302
+ return colorize("Time(#{time})", :time)
303
+
304
+ elsif x.class == BigDecimal
305
+ return colorize("BigDecimal(#{x.to_s('f')})", :bigdecimal)
306
+
307
+ elsif x.class == Rational
308
+ return colorize("Rational(#{x})", :rational)
309
+
310
+ # X is a Structure; essentially a special case of X being an object.
311
+ elsif x.is_a? Struct
312
+ struct_word = colorize('Struct', :struct)
313
+ classname = colorize(x.class, :struct)
314
+ result = "#{struct_word} #{classname}#{@braces ? '(' : ''}\n"
315
+ longest_item = x.members.map { |m| m.to_s.length }.max()
316
+
317
+ x.each_pair do |name, value|
318
+ attr_name = colorize(name.to_s.ljust(longest_item), :attribute)
319
+ attr_data = xpand(value, indent: _indent, tab: tab)
320
+
321
+ result += "#{_indent}#{attr_name} = #{attr_data}\n"
322
+ end
323
+
324
+ result += "#{indent})" if @braces
325
+
326
+ return result
327
+
328
+ # X is any arbitrary object; print all instance variables.
329
+ else
330
+ is_module = x.class == Module
331
+ classname = is_module ? "Module #{x}" : x.class
332
+ classname = colorize(classname, is_module ? :module : :classname)
333
+ result = "#{classname}#{@braces ? '(' : ''}"
334
+ ivars = x.instance_variables
335
+ result += "\n" if ivars.length > 0
336
+ longest_var = ivars.map { |v| v.to_s.length }.max()
337
+
338
+ ivars.each_with_index do |var, index|
339
+ attr_name = var.to_s.ljust(longest_var)
340
+ attr_name = colorize(attr_name, :attribute)
341
+ attr_data = xpand(
342
+ x.instance_variable_get(var),
343
+ indent: _indent,
344
+ tab: tab
345
+ )
346
+
347
+ result += "#{_indent}#{attr_name} = #{attr_data}\n"
348
+ end
349
+
350
+ result += "#{ivars.length > 0 ? indent: ''})" if @braces
351
+
352
+ return result
353
+ end
354
+ end
355
+ end
356
+
357
+ def xp(*args)
358
+ XPrint::xp(*args)
359
+ end
360
+
361
+ def xpand(item, tab: "\t")
362
+ XPrint::xpand(item, tab: tab)
363
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xprint
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.1
5
+ platform: ruby
6
+ authors:
7
+ - JCabr
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-07-21 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Gem that allows for pretty printing data over multiple lines and with
14
+ indentation, and works with objects as well as basic data types. Also allows color,
15
+ and loading settings via a YAML config file.
16
+ email:
17
+ - jcabr.dev@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - lib/version.rb
23
+ - lib/xprint.rb
24
+ homepage: https://github.com/JCabr/xprint.rb
25
+ licenses:
26
+ - MIT
27
+ metadata: {}
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubygems_version: 3.1.2
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: Gem for pretty printing any kind of object.
47
+ test_files: []