xprint 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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: []