awesome_print_lite 0.1.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.
@@ -0,0 +1,174 @@
1
+ # Copyright (c) 2010-2013 Michael Dvorkin
2
+ #
3
+ # Awesome Print is freely distributable under the terms of MIT license.
4
+ # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
5
+ #------------------------------------------------------------------------------
6
+ module AwesomePrintLite
7
+
8
+ class << self # Class accessors for custom defaults.
9
+ attr_accessor :defaults, :force_colors
10
+
11
+ # Class accessor to force colorized output (ex. forked subprocess where TERM
12
+ # might be dumb).
13
+ #------------------------------------------------------------------------------
14
+ def force_colors!(value = true)
15
+ @force_colors = value
16
+ end
17
+
18
+ def console?
19
+ !!(defined?(IRB) || defined?(Pry)|| defined?(OpalIrb))
20
+ end
21
+
22
+ def rails_console?
23
+ console? && !!(defined?(Rails::Console) || ENV["RAILS_ENV"])
24
+ end
25
+ =begin
26
+ def irb!
27
+ return unless defined?(IRB)
28
+ unless IRB.version.include?("DietRB")
29
+ IRB::Irb.class_eval do
30
+ def output_value
31
+ ap @context.last_value
32
+ end
33
+ end
34
+ else # MacRuby
35
+ IRB.formatter = Class.new(IRB::Formatter) do
36
+ def inspect_object(object)
37
+ object.ai
38
+ end
39
+ end.new
40
+ end
41
+ end
42
+
43
+ def pry!
44
+ if defined?(Pry)
45
+ Pry.print = proc { |output, value| output.puts value.ai }
46
+ end
47
+ end
48
+ =end
49
+ end
50
+
51
+ class Inspector
52
+ attr_accessor :options
53
+
54
+ AP = :__awesome_print__
55
+
56
+ def initialize(options = {})
57
+ @options = {
58
+ :indent => 4, # Indent using 4 spaces.
59
+ :index => true, # Display array indices.
60
+ :html => false, # Use ANSI color codes rather than HTML.
61
+ :multiline => true, # Display in multiple lines.
62
+ :plain => false, # Use colors.
63
+ :raw => false, # Do not recursively format object instance variables.
64
+ :sort_keys => false, # Do not sort hash keys.
65
+ :limit => false, # Limit large output for arrays and hashes. Set to a boolean or integer.
66
+ :color => {
67
+ :args => :pale,
68
+ :array => :white,
69
+ :bigdecimal => :blue,
70
+ :class => :yellow,
71
+ :date => :greenish,
72
+ :falseclass => :red,
73
+ :fixnum => :blue,
74
+ :float => :blue,
75
+ :hash => :pale,
76
+ :keyword => :cyan,
77
+ :method => :purpleish,
78
+ :nilclass => :red,
79
+ :rational => :blue,
80
+ :string => :yellowish,
81
+ :struct => :pale,
82
+ :symbol => :cyanish,
83
+ :time => :greenish,
84
+ :trueclass => :green,
85
+ :variable => :cyanish
86
+ }
87
+ }
88
+
89
+ # Merge custom defaults and let explicit options parameter override them.
90
+ if RUBY_ENGINE != 'opal'
91
+ merge_custom_defaults!
92
+ end
93
+ merge_options!(options)
94
+
95
+ @formatter = AwesomePrintLite::Formatter.new(self)
96
+ @ap ||= []
97
+ end
98
+
99
+ # Dispatcher that detects data nesting and invokes object-aware formatter.
100
+ #------------------------------------------------------------------------------
101
+ def awesome(object)
102
+ if @ap.include?(object.object_id)
103
+ nested(object)
104
+ else
105
+ begin
106
+ @ap << object.object_id
107
+ unnested(object)
108
+ ensure
109
+ @ap.pop
110
+ end
111
+ end
112
+ end
113
+
114
+ # Return true if we are to colorize the output.
115
+ #------------------------------------------------------------------------------
116
+ def colorize?
117
+ AwesomePrintLite.force_colors ||= false
118
+ AwesomePrintLite.force_colors || (STDOUT.tty? && ((ENV['TERM'] && ENV['TERM'] != 'dumb') || ENV['ANSICON']))
119
+ end
120
+
121
+ private
122
+
123
+ # Format nested data, for example:
124
+ # arr = [1, 2]; arr << arr
125
+ # => [1,2, [...]]
126
+ # hash = { :a => 1 }; hash[:b] = hash
127
+ # => { :a => 1, :b => {...} }
128
+ #------------------------------------------------------------------------------
129
+ def nested(object)
130
+ case printable(object)
131
+ when :array then @formatter.colorize("[...]", :array)
132
+ when :hash then @formatter.colorize("{...}", :hash)
133
+ when :struct then @formatter.colorize("{...}", :struct)
134
+ else @formatter.colorize("...#{object.class}...", :class)
135
+ end
136
+ end
137
+
138
+ #------------------------------------------------------------------------------
139
+ def unnested(object)
140
+ @formatter.format(object, printable(object))
141
+ end
142
+
143
+ # Turn class name into symbol, ex: Hello::World => :hello_world. Classes that
144
+ # inherit from Array, Hash, File, Dir, and Struct are treated as the base class.
145
+ #------------------------------------------------------------------------------
146
+ def printable(object)
147
+ case object
148
+ when Array then :array
149
+ when Hash then :hash
150
+ when File then :file
151
+ when Dir then :dir
152
+ when Struct then :struct
153
+ else object.class.to_s.gsub(/:+/, "_").downcase.to_sym
154
+ end
155
+ end
156
+
157
+ # Update @options by first merging the :color hash and then the remaining keys.
158
+ #------------------------------------------------------------------------------
159
+ def merge_options!(options = {})
160
+ @options[:color].merge!(options.delete(:color) || {})
161
+ @options.merge!(options)
162
+ end
163
+
164
+ # Load ~/.aprc file with custom defaults that override default options.
165
+ #------------------------------------------------------------------------------
166
+ def merge_custom_defaults!
167
+ dotfile = File.join(ENV["HOME"], ".aprc")
168
+ load dotfile if File.readable?(dotfile)
169
+ merge_options!(AwesomePrintLite.defaults) if AwesomePrintLite.defaults.is_a?(Hash)
170
+ rescue => e
171
+ $stderr.puts "Could not load #{dotfile}: #{e}"
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,3 @@
1
+ module AwesomePrintLite
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe "AwesomePrint" do
4
+ def stub_tty!(output = true, stream = STDOUT)
5
+ if output
6
+ stream.instance_eval { def tty?; true; end }
7
+ else
8
+ stream.instance_eval { def tty?; false; end }
9
+ end
10
+ end
11
+
12
+ before do
13
+ stub_dotfile!
14
+ end
15
+
16
+ describe "colorization" do
17
+ PLAIN = '[ 1, :two, "three", [ nil, [ true, false ] ] ]'
18
+ COLORIZED = "[ \e[1;34m1\e[0m, \e[0;36m:two\e[0m, \e[0;33m\"three\"\e[0m, [ \e[1;31mnil\e[0m, [ \e[1;32mtrue\e[0m, \e[1;31mfalse\e[0m ] ] ]"
19
+
20
+ before do
21
+ ENV['TERM'] = "xterm-colors"
22
+ ENV.delete('ANSICON')
23
+ @arr = [ 1, :two, "three", [ nil, [ true, false] ] ]
24
+ end
25
+
26
+ describe "default settings (no forced colors)" do
27
+ before do
28
+ AwesomePrintLite.force_colors! false
29
+ end
30
+
31
+ it "colorizes tty processes by default" do
32
+ stub_tty!
33
+ expect(@arr.ai(:multiline => false)).to eq(COLORIZED)
34
+ end
35
+
36
+ it "colorizes processes with ENV['ANSICON'] by default" do
37
+ begin
38
+ stub_tty!
39
+ term, ENV['ANSICON'] = ENV['ANSICON'], "1"
40
+ expect(@arr.ai(:multiline => false)).to eq(COLORIZED)
41
+ ensure
42
+ ENV['ANSICON'] = term
43
+ end
44
+ end
45
+
46
+ it "does not colorize tty processes running in dumb terminals by default" do
47
+ begin
48
+ stub_tty!
49
+ term, ENV['TERM'] = ENV['TERM'], "dumb"
50
+ expect(@arr.ai(:multiline => false)).to eq(PLAIN)
51
+ ensure
52
+ ENV['TERM'] = term
53
+ end
54
+ end
55
+
56
+ it "does not colorize subprocesses by default" do
57
+ begin
58
+ stub_tty! false
59
+ expect(@arr.ai(:multiline => false)).to eq(PLAIN)
60
+ ensure
61
+ stub_tty!
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "forced colors override" do
67
+ before do
68
+ AwesomePrintLite.force_colors!
69
+ end
70
+
71
+ it "still colorizes tty processes" do
72
+ stub_tty!
73
+ expect(@arr.ai(:multiline => false)).to eq(COLORIZED)
74
+ end
75
+
76
+ it "colorizes processes with ENV['ANSICON'] set to 0" do
77
+ begin
78
+ stub_tty!
79
+ term, ENV['ANSICON'] = ENV['ANSICON'], "1"
80
+ expect(@arr.ai(:multiline => false)).to eq(COLORIZED)
81
+ ensure
82
+ ENV['ANSICON'] = term
83
+ end
84
+ end
85
+
86
+ it "colorizes dumb terminals" do
87
+ begin
88
+ stub_tty!
89
+ term, ENV['TERM'] = ENV['TERM'], "dumb"
90
+ expect(@arr.ai(:multiline => false)).to eq(COLORIZED)
91
+ ensure
92
+ ENV['TERM'] = term
93
+ end
94
+ end
95
+
96
+ it "colorizes subprocess" do
97
+ begin
98
+ stub_tty! false
99
+ expect(@arr.ai(:multiline => false)).to eq(COLORIZED)
100
+ ensure
101
+ stub_tty!
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe "String extensions" do
4
+ [ :gray, :red, :green, :yellow, :blue, :purple, :cyan, :white ].each_with_index do |color, i|
5
+ it "should have #{color} color" do
6
+ expect(color.to_s.send(color)).to eq("\e[1;#{30+i}m#{color}\e[0m")
7
+ end
8
+
9
+ it "should have #{color}ish color" do
10
+ expect(color.to_s.send(:"#{color}ish")).to eq("\e[0;#{30+i}m#{color}\e[0m")
11
+ end
12
+ end
13
+
14
+ it "should have black and pale colors" do
15
+ expect("black".send(:black)).to eq("black".send(:grayish))
16
+ expect("pale".send(:pale)).to eq("pale".send(:whiteish))
17
+ expect("pale".send(:pale)).to eq("\e[0;37mpale\e[0m")
18
+ expect("whiteish".send(:whiteish)).to eq("\e[0;37mwhiteish\e[0m")
19
+ end
20
+ end
@@ -0,0 +1,725 @@
1
+ require 'spec_helper'
2
+ require "set"
3
+
4
+ RSpec.describe "AwesomePrint" do
5
+ before do
6
+ stub_dotfile!
7
+ end
8
+
9
+ describe "Array" do
10
+ before do
11
+ @arr = [ 1, :two, "three", [ nil, [ true, false] ] ]
12
+ end
13
+
14
+ it "empty array" do
15
+ expect([].ai).to eq("[]")
16
+ end
17
+
18
+ it "plain multiline" do
19
+ expect(@arr.ai(:plain => true)).to eq <<-EOS.strip
20
+ [
21
+ [0] 1,
22
+ [1] :two,
23
+ [2] "three",
24
+ [3] [
25
+ [0] nil,
26
+ [1] [
27
+ [0] true,
28
+ [1] false
29
+ ]
30
+ ]
31
+ ]
32
+ EOS
33
+ end
34
+
35
+ it "plain multiline without index" do
36
+ expect(@arr.ai(:plain => true, :index => false)).to eq <<-EOS.strip
37
+ [
38
+ 1,
39
+ :two,
40
+ "three",
41
+ [
42
+ nil,
43
+ [
44
+ true,
45
+ false
46
+ ]
47
+ ]
48
+ ]
49
+ EOS
50
+ end
51
+
52
+ it "plain multiline indented" do
53
+ expect(@arr.ai(:plain => true, :indent => 2)).to eq <<-EOS.strip
54
+ [
55
+ [0] 1,
56
+ [1] :two,
57
+ [2] "three",
58
+ [3] [
59
+ [0] nil,
60
+ [1] [
61
+ [0] true,
62
+ [1] false
63
+ ]
64
+ ]
65
+ ]
66
+ EOS
67
+ end
68
+
69
+ it "plain multiline indented without index" do
70
+ expect(@arr.ai(:plain => true, :indent => 2, :index => false)).to eq <<-EOS.strip
71
+ [
72
+ 1,
73
+ :two,
74
+ "three",
75
+ [
76
+ nil,
77
+ [
78
+ true,
79
+ false
80
+ ]
81
+ ]
82
+ ]
83
+ EOS
84
+ end
85
+
86
+ it "plain single line" do
87
+ expect(@arr.ai(:plain => true, :multiline => false)).to eq('[ 1, :two, "three", [ nil, [ true, false ] ] ]')
88
+ end
89
+
90
+ it "colored multiline (default)" do
91
+ expect(@arr.ai).to eq <<-EOS.strip
92
+ [
93
+ \e[1;37m[0] \e[0m\e[1;34m1\e[0m,
94
+ \e[1;37m[1] \e[0m\e[0;36m:two\e[0m,
95
+ \e[1;37m[2] \e[0m\e[0;33m\"three\"\e[0m,
96
+ \e[1;37m[3] \e[0m[
97
+ \e[1;37m[0] \e[0m\e[1;31mnil\e[0m,
98
+ \e[1;37m[1] \e[0m[
99
+ \e[1;37m[0] \e[0m\e[1;32mtrue\e[0m,
100
+ \e[1;37m[1] \e[0m\e[1;31mfalse\e[0m
101
+ ]
102
+ ]
103
+ ]
104
+ EOS
105
+ end
106
+
107
+ it "colored multiline indented" do
108
+ expect(@arr.ai(:indent => 8)).to eq <<-EOS.strip
109
+ [
110
+ \e[1;37m[0] \e[0m\e[1;34m1\e[0m,
111
+ \e[1;37m[1] \e[0m\e[0;36m:two\e[0m,
112
+ \e[1;37m[2] \e[0m\e[0;33m\"three\"\e[0m,
113
+ \e[1;37m[3] \e[0m[
114
+ \e[1;37m[0] \e[0m\e[1;31mnil\e[0m,
115
+ \e[1;37m[1] \e[0m[
116
+ \e[1;37m[0] \e[0m\e[1;32mtrue\e[0m,
117
+ \e[1;37m[1] \e[0m\e[1;31mfalse\e[0m
118
+ ]
119
+ ]
120
+ ]
121
+ EOS
122
+ end
123
+
124
+ it "colored single line" do
125
+ expect(@arr.ai(:multiline => false)).to eq("[ \e[1;34m1\e[0m, \e[0;36m:two\e[0m, \e[0;33m\"three\"\e[0m, [ \e[1;31mnil\e[0m, [ \e[1;32mtrue\e[0m, \e[1;31mfalse\e[0m ] ] ]")
126
+ end
127
+ end
128
+
129
+ #------------------------------------------------------------------------------
130
+ describe "Nested Array" do
131
+ before do
132
+ @arr = [ 1, 2 ]
133
+ @arr << @arr
134
+ end
135
+
136
+ it "plain multiline" do
137
+ expect(@arr.ai(:plain => true)).to eq <<-EOS.strip
138
+ [
139
+ [0] 1,
140
+ [1] 2,
141
+ [2] [...]
142
+ ]
143
+ EOS
144
+ end
145
+
146
+ it "plain multiline without index" do
147
+ expect(@arr.ai(:plain => true, :index => false)).to eq <<-EOS.strip
148
+ [
149
+ 1,
150
+ 2,
151
+ [...]
152
+ ]
153
+ EOS
154
+ end
155
+
156
+ it "plain single line" do
157
+ expect(@arr.ai(:plain => true, :multiline => false)).to eq("[ 1, 2, [...] ]")
158
+ end
159
+ end
160
+
161
+ #------------------------------------------------------------------------------
162
+ describe "Limited Output Array" do
163
+ before(:each) do
164
+ @arr = (1..1000).to_a
165
+ end
166
+
167
+ it "plain limited output large" do
168
+ expect(@arr.ai(:plain => true, :limit => true)).to eq <<-EOS.strip
169
+ [
170
+ [ 0] 1,
171
+ [ 1] 2,
172
+ [ 2] 3,
173
+ [ 3] .. [996],
174
+ [997] 998,
175
+ [998] 999,
176
+ [999] 1000
177
+ ]
178
+ EOS
179
+ end
180
+
181
+ it "plain limited output small" do
182
+ @arr = @arr[0..3]
183
+ expect(@arr.ai(:plain => true, :limit => true)).to eq <<-EOS.strip
184
+ [
185
+ [0] 1,
186
+ [1] 2,
187
+ [2] 3,
188
+ [3] 4
189
+ ]
190
+ EOS
191
+ end
192
+
193
+ it "plain limited output with 10 lines" do
194
+ expect(@arr.ai(:plain => true, :limit => 10)).to eq <<-EOS.strip
195
+ [
196
+ [ 0] 1,
197
+ [ 1] 2,
198
+ [ 2] 3,
199
+ [ 3] 4,
200
+ [ 4] 5,
201
+ [ 5] .. [995],
202
+ [996] 997,
203
+ [997] 998,
204
+ [998] 999,
205
+ [999] 1000
206
+ ]
207
+ EOS
208
+ end
209
+
210
+ it "plain limited output with 11 lines" do
211
+ expect(@arr.ai(:plain => true, :limit => 11)).to eq <<-EOS.strip
212
+ [
213
+ [ 0] 1,
214
+ [ 1] 2,
215
+ [ 2] 3,
216
+ [ 3] 4,
217
+ [ 4] 5,
218
+ [ 5] .. [994],
219
+ [995] 996,
220
+ [996] 997,
221
+ [997] 998,
222
+ [998] 999,
223
+ [999] 1000
224
+ ]
225
+ EOS
226
+ end
227
+ end
228
+
229
+ #------------------------------------------------------------------------------
230
+ describe "Limited Output Hash" do
231
+ before(:each) do
232
+ @hash = ("a".."z").inject({}) { |h, v| h.merge({ v => v.to_sym }) }
233
+ end
234
+
235
+ it "plain limited output" do
236
+ expect(@hash.ai(:sort_keys => true, :plain => true, :limit => true)).to eq <<-EOS.strip
237
+ {
238
+ "a" => :a,
239
+ "b" => :b,
240
+ "c" => :c,
241
+ "d" => :d .. "w" => :w,
242
+ "x" => :x,
243
+ "y" => :y,
244
+ "z" => :z
245
+ }
246
+ EOS
247
+ end
248
+ end
249
+
250
+ #------------------------------------------------------------------------------
251
+ describe "Hash" do
252
+ before do
253
+ @hash = { 1 => { :sym => { "str" => { [1, 2, 3] => { { :k => :v } => Hash } } } } }
254
+ end
255
+
256
+ it "empty hash" do
257
+ expect({}.ai).to eq("{}")
258
+ end
259
+
260
+ it "plain multiline" do
261
+ expect(@hash.ai(:plain => true)).to eq <<-EOS.strip
262
+ {
263
+ 1 => {
264
+ :sym => {
265
+ "str" => {
266
+ [ 1, 2, 3 ] => {
267
+ { :k => :v } => Hash < Object
268
+ }
269
+ }
270
+ }
271
+ }
272
+ }
273
+ EOS
274
+ end
275
+
276
+ it "plain multiline indented" do
277
+ expect(@hash.ai(:plain => true, :indent => 1)).to eq <<-EOS.strip
278
+ {
279
+ 1 => {
280
+ :sym => {
281
+ "str" => {
282
+ [ 1, 2, 3 ] => {
283
+ { :k => :v } => Hash < Object
284
+ }
285
+ }
286
+ }
287
+ }
288
+ }
289
+ EOS
290
+ end
291
+
292
+ it "plain single line" do
293
+ expect(@hash.ai(:plain => true, :multiline => false)).to eq('{ 1 => { :sym => { "str" => { [ 1, 2, 3 ] => { { :k => :v } => Hash < Object } } } } }')
294
+ end
295
+
296
+ it "colored multiline (default)" do
297
+ expect(@hash.ai).to eq <<-EOS.strip
298
+ {
299
+ 1\e[0;37m => \e[0m{
300
+ :sym\e[0;37m => \e[0m{
301
+ \"str\"\e[0;37m => \e[0m{
302
+ [ 1, 2, 3 ]\e[0;37m => \e[0m{
303
+ { :k => :v }\e[0;37m => \e[0m\e[1;33mHash < Object\e[0m
304
+ }
305
+ }
306
+ }
307
+ }
308
+ }
309
+ EOS
310
+ end
311
+
312
+ it "colored multiline indented" do
313
+ expect(@hash.ai(:indent => 2)).to eq <<-EOS.strip
314
+ {
315
+ 1\e[0;37m => \e[0m{
316
+ :sym\e[0;37m => \e[0m{
317
+ \"str\"\e[0;37m => \e[0m{
318
+ [ 1, 2, 3 ]\e[0;37m => \e[0m{
319
+ { :k => :v }\e[0;37m => \e[0m\e[1;33mHash < Object\e[0m
320
+ }
321
+ }
322
+ }
323
+ }
324
+ }
325
+ EOS
326
+ end
327
+
328
+ it "colored single line" do
329
+ expect(@hash.ai(:multiline => false)).to eq("{ 1\e[0;37m => \e[0m{ :sym\e[0;37m => \e[0m{ \"str\"\e[0;37m => \e[0m{ [ 1, 2, 3 ]\e[0;37m => \e[0m{ { :k => :v }\e[0;37m => \e[0m\e[1;33mHash < Object\e[0m } } } } }")
330
+ end
331
+
332
+ end
333
+
334
+ #------------------------------------------------------------------------------
335
+ describe "Nested Hash" do
336
+ before do
337
+ @hash = {}
338
+ @hash[:a] = @hash
339
+ end
340
+
341
+ it "plain multiline" do
342
+ expect(@hash.ai(:plain => true)).to eq <<-EOS.strip
343
+ {
344
+ :a => {...}
345
+ }
346
+ EOS
347
+ end
348
+
349
+ it "plain single line" do
350
+ expect(@hash.ai(:plain => true, :multiline => false)).to eq('{ :a => {...} }')
351
+ end
352
+ end
353
+
354
+ #------------------------------------------------------------------------------
355
+ describe "Hash with several keys" do
356
+ before do
357
+ @hash = {"b" => "b", :a => "a", :z => "z", "alpha" => "alpha"}
358
+ end
359
+
360
+ it "plain multiline" do
361
+ out = @hash.ai(:plain => true)
362
+ if RUBY_VERSION.to_f < 1.9 # Order of @hash keys is not guaranteed.
363
+ expect(out).to match(/^\{[^\}]+\}/m)
364
+ expect(out).to match(/ "b" => "b",?/)
365
+ expect(out).to match(/ :a => "a",?/)
366
+ expect(out).to match(/ :z => "z",?/)
367
+ expect(out).to match(/ "alpha" => "alpha",?$/)
368
+ else
369
+ expect(out).to eq <<-EOS.strip
370
+ {
371
+ "b" => "b",
372
+ :a => "a",
373
+ :z => "z",
374
+ "alpha" => "alpha"
375
+ }
376
+ EOS
377
+ end
378
+ end
379
+
380
+ it "plain multiline with sorted keys" do
381
+ expect(@hash.ai(:plain => true, :sort_keys => true)).to eq <<-EOS.strip
382
+ {
383
+ :a => "a",
384
+ "alpha" => "alpha",
385
+ "b" => "b",
386
+ :z => "z"
387
+ }
388
+ EOS
389
+ end
390
+
391
+ end
392
+
393
+ #------------------------------------------------------------------------------
394
+ describe "Negative options[:indent]" do
395
+ #
396
+ # With Ruby < 1.9 the order of hash keys is not defined so we can't
397
+ # reliably compare the output string.
398
+ #
399
+ it "hash keys must be left aligned" do
400
+ hash = { [0, 0, 255] => :yellow, :red => "rgb(255, 0, 0)", "magenta" => "rgb(255, 0, 255)" }
401
+ out = hash.ai(:plain => true, :indent => -4, :sort_keys => true)
402
+ expect(out).to eq <<-EOS.strip
403
+ {
404
+ [ 0, 0, 255 ] => :yellow,
405
+ "magenta" => "rgb(255, 0, 255)",
406
+ :red => "rgb(255, 0, 0)"
407
+ }
408
+ EOS
409
+ end
410
+
411
+ it "nested hash keys should be indented (array of hashes)" do
412
+ arr = [ { :a => 1, :bb => 22, :ccc => 333}, { 1 => :a, 22 => :bb, 333 => :ccc} ]
413
+ out = arr.ai(:plain => true, :indent => -4, :sort_keys => true)
414
+ expect(out).to eq <<-EOS.strip
415
+ [
416
+ [0] {
417
+ :a => 1,
418
+ :bb => 22,
419
+ :ccc => 333
420
+ },
421
+ [1] {
422
+ 1 => :a,
423
+ 22 => :bb,
424
+ 333 => :ccc
425
+ }
426
+ ]
427
+ EOS
428
+ end
429
+
430
+ it "nested hash keys should be indented (hash of hashes)" do
431
+ arr = { :first => { :a => 1, :bb => 22, :ccc => 333}, :second => { 1 => :a, 22 => :bb, 333 => :ccc} }
432
+ out = arr.ai(:plain => true, :indent => -4, :sort_keys => true)
433
+ expect(out).to eq <<-EOS.strip
434
+ {
435
+ :first => {
436
+ :a => 1,
437
+ :bb => 22,
438
+ :ccc => 333
439
+ },
440
+ :second => {
441
+ 1 => :a,
442
+ 22 => :bb,
443
+ 333 => :ccc
444
+ }
445
+ }
446
+ EOS
447
+ end
448
+ end
449
+
450
+ #------------------------------------------------------------------------------
451
+ describe "Class" do
452
+ it "shoud show superclass (plain)" do
453
+ expect(self.class.ai(:plain => true)).to eq("#{self.class} < #{self.class.superclass}")
454
+ end
455
+
456
+ it "shoud show superclass (color)" do
457
+ expect(self.class.ai).to eq("#{self.class} < #{self.class.superclass}".yellow)
458
+ end
459
+ end
460
+
461
+ #------------------------------------------------------------------------------
462
+ describe "Rational" do
463
+
464
+ it "should present Rational object with arbitrary precision" do
465
+ rat = Rational(201020102010201020102010201020102010, 2)
466
+ out = rat.ai(:plain => true)
467
+ #
468
+ # Ruby 1.9 slightly changed the format of Rational#to_s, see
469
+ # http://techtime.getharvest.com/blog/harvest-is-now-on-ruby-1-dot-9-3 and
470
+ # http://www.ruby-forum.com/topic/189397
471
+ #
472
+ if RUBY_VERSION < "1.9"
473
+ expect(out).to eq("100510051005100510051005100510051005")
474
+ else
475
+ expect(out).to eq("100510051005100510051005100510051005/1")
476
+ end
477
+ end
478
+ end
479
+
480
+ #------------------------------------------------------------------------------
481
+ describe "Utility methods" do
482
+ it "should merge options" do
483
+ ap = AwesomePrintLite::Inspector.new
484
+ ap.send(:merge_options!, { :color => { :array => :black }, :indent => 0 })
485
+ options = ap.instance_variable_get("@options")
486
+ expect(options[:color][:array]).to eq(:black)
487
+ expect(options[:indent]).to eq(0)
488
+ end
489
+ end
490
+
491
+ #------------------------------------------------------------------------------
492
+ describe "Set" do
493
+ before do
494
+ @arr = [1, :two, "three" ]
495
+ @set = Set.new(@arr)
496
+ end
497
+
498
+ it "empty set" do
499
+ expect(Set.new.ai).to eq([].ai)
500
+ end
501
+
502
+ if RUBY_VERSION > "1.9"
503
+ it "plain multiline" do
504
+ expect(@set.ai(:plain => true)).to eq(@arr.ai(:plain => true))
505
+ end
506
+
507
+ it "plain multiline indented" do
508
+ expect(@set.ai(:plain => true, :indent => 1)).to eq(@arr.ai(:plain => true, :indent => 1))
509
+ end
510
+
511
+ it "plain single line" do
512
+ expect(@set.ai(:plain => true, :multiline => false)).to eq(@arr.ai(:plain => true, :multiline => false))
513
+ end
514
+
515
+ it "colored multiline (default)" do
516
+ expect(@set.ai).to eq(@arr.ai)
517
+ end
518
+ else # Prior to Ruby 1.9 the order of set values is unpredicatble.
519
+ it "plain multiline" do
520
+ expect(@set.sort_by{ |x| x.to_s }.ai(:plain => true)).to eq(@arr.sort_by{ |x| x.to_s }.ai(:plain => true))
521
+ end
522
+
523
+ it "plain multiline indented" do
524
+ expect(@set.sort_by{ |x| x.to_s }.ai(:plain => true, :indent => 1)).to eq(@arr.sort_by{ |x| x.to_s }.ai(:plain => true, :indent => 1))
525
+ end
526
+
527
+ it "plain single line" do
528
+ expect(@set.sort_by{ |x| x.to_s }.ai(:plain => true, :multiline => false)).to eq(@arr.sort_by{ |x| x.to_s }.ai(:plain => true, :multiline => false))
529
+ end
530
+
531
+ it "colored multiline (default)" do
532
+ expect(@set.sort_by{ |x| x.to_s }.ai).to eq(@arr.sort_by{ |x| x.to_s }.ai)
533
+ end
534
+ end
535
+ end
536
+
537
+ #------------------------------------------------------------------------------
538
+ describe "Struct" do
539
+ before do
540
+ @struct = unless defined?(Struct::SimpleStruct)
541
+ Struct.new("SimpleStruct", :name, :address).new
542
+ else
543
+ Struct::SimpleStruct.new
544
+ end
545
+ @struct.name = "Herman Munster"
546
+ @struct.address = "1313 Mockingbird Lane"
547
+ end
548
+
549
+ it "empty struct" do
550
+ expect(Struct.new("EmptyStruct").ai).to eq("\e[1;33mStruct::EmptyStruct < Struct\e[0m")
551
+ end
552
+
553
+ it "plain multiline" do
554
+ s1 = <<-EOS.strip
555
+ {
556
+ :address => "1313 Mockingbird Lane",
557
+ :name => "Herman Munster"
558
+ }
559
+ EOS
560
+ s2 = <<-EOS.strip
561
+ {
562
+ :name => "Herman Munster",
563
+ :address => "1313 Mockingbird Lane"
564
+ }
565
+ EOS
566
+ expect(@struct.ai(:plain => true)).to satisfy { |match| match == s1 || match == s2 }
567
+ end
568
+
569
+ it "plain multiline indented" do
570
+ s1 = <<-EOS.strip
571
+ {
572
+ :address => "1313 Mockingbird Lane",
573
+ :name => "Herman Munster"
574
+ }
575
+ EOS
576
+ s2 = <<-EOS.strip
577
+ {
578
+ :name => "Herman Munster",
579
+ :address => "1313 Mockingbird Lane"
580
+ }
581
+ EOS
582
+ expect(@struct.ai(:plain => true, :indent => 1)).to satisfy { |match| match == s1 || match == s2 }
583
+ end
584
+
585
+ it "plain single line" do
586
+ s1 = "{ :address => \"1313 Mockingbird Lane\", :name => \"Herman Munster\" }"
587
+ s2 = "{ :name => \"Herman Munster\", :address => \"1313 Mockingbird Lane\" }"
588
+ expect(@struct.ai(:plain => true, :multiline => false)).to satisfy { |match| match == s1 || match == s2 }
589
+ end
590
+
591
+ it "colored multiline (default)" do
592
+ s1 = <<-EOS.strip
593
+ {
594
+ :address\e[0;37m => \e[0m\e[0;33m\"1313 Mockingbird Lane\"\e[0m,
595
+ :name\e[0;37m => \e[0m\e[0;33m\"Herman Munster\"\e[0m
596
+ }
597
+ EOS
598
+ s2 = <<-EOS.strip
599
+ {
600
+ :name\e[0;37m => \e[0m\e[0;33m\"Herman Munster\"\e[0m,
601
+ :address\e[0;37m => \e[0m\e[0;33m\"1313 Mockingbird Lane\"\e[0m
602
+ }
603
+ EOS
604
+ expect(@struct.ai).to satisfy { |match| match == s1 || match == s2 }
605
+ end
606
+ end
607
+
608
+ #------------------------------------------------------------------------------
609
+ describe "Inherited from standard Ruby classes" do
610
+ after do
611
+ Object.instance_eval{ remove_const :My } if defined?(My)
612
+ end
613
+
614
+ it "inherited from Array should be displayed as Array" do
615
+ class My < Array; end
616
+
617
+ my = My.new([ 1, :two, "three", [ nil, [ true, false ] ] ])
618
+ expect(my.ai(:plain => true)).to eq <<-EOS.strip
619
+ [
620
+ [0] 1,
621
+ [1] :two,
622
+ [2] "three",
623
+ [3] [
624
+ [0] nil,
625
+ [1] [
626
+ [0] true,
627
+ [1] false
628
+ ]
629
+ ]
630
+ ]
631
+ EOS
632
+ end
633
+
634
+ it "inherited from Hash should be displayed as Hash" do
635
+ class My < Hash; end
636
+
637
+ my = My[ { 1 => { :sym => { "str" => { [1, 2, 3] => { { :k => :v } => Hash } } } } } ]
638
+ expect(my.ai(:plain => true)).to eq <<-EOS.strip
639
+ {
640
+ 1 => {
641
+ :sym => {
642
+ "str" => {
643
+ [ 1, 2, 3 ] => {
644
+ { :k => :v } => Hash < Object
645
+ }
646
+ }
647
+ }
648
+ }
649
+ }
650
+ EOS
651
+ end
652
+
653
+
654
+ it "should handle a class that defines its own #send method" do
655
+ class My
656
+ def send(arg1, arg2, arg3); end
657
+ end
658
+
659
+ my = My.new
660
+ expect { my.methods.ai(:plain => true) }.not_to raise_error
661
+ end
662
+
663
+ it "should handle a class defines its own #method method (ex. request.method)" do
664
+ class My
665
+ def method
666
+ 'POST'
667
+ end
668
+ end
669
+
670
+ my = My.new
671
+ expect { my.methods.ai(:plain => true) }.not_to raise_error
672
+ end
673
+
674
+ describe "should handle a class that defines its own #to_hash method" do
675
+ it "that takes arguments" do
676
+ class My
677
+ def to_hash(a, b)
678
+ end
679
+ end
680
+
681
+ my = My.new
682
+ expect { my.ai(:plain => true) }.not_to raise_error
683
+ end
684
+
685
+ it "that returns nil" do
686
+ class My
687
+ def to_hash()
688
+ return nil
689
+ end
690
+ end
691
+
692
+ my = My.new
693
+ expect { my.ai(:plain => true) }.not_to raise_error
694
+ end
695
+
696
+ it "that returns an object that doesn't support #keys" do
697
+ class My
698
+ def to_hash()
699
+ object = Object.new
700
+ object.define_singleton_method('[]') { return nil }
701
+
702
+ return object
703
+ end
704
+ end
705
+
706
+ my = My.new
707
+ expect { my.ai(:plain => true) }.not_to raise_error
708
+ end
709
+
710
+ it "that returns an object that doesn't support subscripting" do
711
+ class My
712
+ def to_hash()
713
+ object = Object.new
714
+ object.define_singleton_method(:keys) { return [:foo] }
715
+
716
+ return object
717
+ end
718
+ end
719
+
720
+ my = My.new
721
+ expect { my.ai(:plain => true) }.not_to raise_error
722
+ end
723
+ end
724
+ end
725
+ end