awesome_print_lite 0.1.0

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