spraints (owner)

Revisions

gist: 158795 Download_button fork
public
Description:
Ruby's inspect for .NET
Public Clone URL: git://gist.github.com/158795.git
Embed All Files: show embed
InspectExtensions.cs #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
using System;
using System.Collections;
using System.Linq;
using System.Text.RegularExpressions;
 
namespace SEP.Extensions
{
    public static class InspectExtensions
    {
        public static string Inspect(this object obj)
        {
            return Inspect(obj, d => d.Inspect(), e => e.Inspect(), o => InspectWithProperties(o));
        }
 
        public static string Inspect(this char o)
        {
            return "'" + o + "'";
        }
 
        public static string Inspect(this string o)
        {
            if (o == null) return Inspect((object)o);
            return "\"" + o + "\"";
        }
 
        public static string Inspect(this IDictionary o)
        {
            if (o == null) return Inspect((object)o);
            var entries = o.Keys.Cast<object>().Select(key => InspectSimple(key) + " => " + InspectSimple(o[key]));
            return "{" + String.Join(", ", entries.ToArray()) + "}";
        }
 
        public static string Inspect(this IEnumerable o)
        {
            if (o == null) return Inspect((object)o);
            return "[" + String.Join(", ", o.Cast<object>().Select(obj => InspectSimple(obj)).ToArray()) + "]";
        }
 
        private static string InspectWithProperties(object o)
        {
            var inspected = "#<";
            inspected += InspectType(o.GetType());
            inspected += String.Join(",",
                                     o.GetType().GetProperties().Select(p => " " + p.Name + "=" + InspectSimple(p.GetValue(o, null)))
                                         .ToArray());
            inspected += ">";
            return inspected;
        }
 
        private static string InspectSimple(object obj)
        {
            return Inspect(obj, d => "{...}", e => "[...]",
                           o => "#<" + InspectType(o.GetType()) + ":0x" + o.GetHashCode().ToString("x") + ">");
        }
 
        private static string Inspect(object o,
            Func<IDictionary, string> inspectDictionary,
            Func<IEnumerable, string> inspectEnumerable,
            Func<object, string> inspectObject)
        {
            if (o == null) return "null";
            if (ShouldUseToString(o)) return o.ToString();
            if (o is Enum) return o.ToString().Replace(", ", "|");
            if (o is String) return ((String) o).Inspect();
            if (o is char) return ((char) o).Inspect();
            if (CanInspect(o)) return CallInspect(o);
            if (o is IDictionary) return inspectDictionary((IDictionary) o);
            if (o is IEnumerable) return inspectEnumerable((IEnumerable)o);
            return inspectObject(o);
        }
 
        private static bool ShouldUseToString(object o)
        {
            return o is int ||
                   o is long ||
                   o is float ||
                   o is double ||
                   o is decimal ||
                   o is byte ||
                   o is DateTime;
        }
 
        private static bool CanInspect(object o)
        {
            var inspectMethod = o.GetType().GetMethod("Inspect", new Type[0]);
            return inspectMethod != null && inspectMethod.ReturnType == typeof (String);
        }
 
        private static string CallInspect(object o)
        {
            var inspectMethod = o.GetType().GetMethod("Inspect", new Type[0]);
            return (string) inspectMethod.Invoke(o, null);
        }
 
        private static string InspectType(Type type)
        {
            return IsAnonymousType(type) ? InspectAnonymousType(type) : type.IsGenericType ? InspectGenericType(type) : type.FullName;
        }
 
        private static bool IsAnonymousType(Type type)
        {
            return new Regex("^<>f__AnonymousType").IsMatch(type.FullName);
        }
 
        private static string InspectAnonymousType(Type type)
        {
            return "anon";
        }
 
        private static string InspectGenericType(Type type)
        {
            var name = Undecorate(type.FullName);
            name += "<";
            name += String.Join(",", type.GetGenericArguments().Select(t => InspectType(t)).ToArray());
            name += ">";
            return name;
        }
 
        private static string Undecorate(string genericTypeName)
        {
            var decorationMatcher = new Regex(@"`\d+\[\[[^\]]+\](,\[[^\]]+\])*\]");
            return decorationMatcher.Replace(genericTypeName, "");
        }
    }
}
 
InspectExtensionTests.cs #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
 
namespace SEP.Extensions.Tests
{
[TestClass]
    public class InspectExtensionTests
    {
[TestMethod]
        public void ShouldInspectNull()
        {
            object o = null;
            Assert.AreEqual("null", o.Inspect());
        }
 
[TestMethod]
        public void ShouldInspectBytes()
        {
            byte b = 0x80;
            Assert.AreEqual("128", b.Inspect());
        }
 
[TestMethod]
        public void ShouldInspectChars()
        {
            Assert.AreEqual("'a'", 'a'.Inspect());
        }
 
[TestMethod]
        public void ShouldInspectIntegers()
        {
            Assert.AreEqual("99", 99.Inspect());
        }
 
[TestMethod]
        public void ShouldInspectLongs()
        {
            Assert.AreEqual("9999", 9999L.Inspect());
        }
 
[TestMethod]
        public void ShouldInspectStrings()
        {
            Assert.AreEqual("\"hello!\"", "hello!".Inspect());
        }
 
[TestMethod]
        public void ShouldInspectFloats()
        {
            Assert.AreEqual("1.5", 1.5F.Inspect());
        }
 
[TestMethod]
        public void ShouldInspectDoubles()
        {
            Assert.AreEqual("1.5", 1.5.Inspect());
        }
 
[TestMethod]
        public void ShouldInspectDecimals()
        {
            Assert.AreEqual("1.5", new Decimal(1.5).Inspect());
        }
 
[TestMethod]
        public void ShouldInspectDateTime()
        {
            Assert.AreEqual("1/1/2009 12:00:00 AM", new DateTime(2009, 1, 1).Inspect());
        }
 
[TestMethod]
        public void ShouldInspectStringPretendingToBeAnObject()
        {
            object o = "hello!";
            Assert.AreEqual("\"hello!\"", o.Inspect());
        }
 
[TestMethod]
        public void ShouldInspectArray()
        {
            Assert.AreEqual("[1, 2, 3]", new object[] {1, 2, 3}.Inspect());
        }
 
[TestMethod]
        public void ShouldInspectList()
        {
            Assert.AreEqual("[1, 2, 3]", new List<object>() {1, 2, 3}.Inspect());
        }
 
[TestMethod]
        public void ShouldInspectDictionary()
        {
            var items = new Dictionary<string, int>() {{"key", 1}};
            Assert.AreEqual("{\"key\" => 1}", items.Inspect());
        }
 
[TestMethod]
        public void ShouldReportProperties()
        {
            Assert.AreEqual("#<anon Name=\"Matt\", Level=4>", new {Name = "Matt", Level = 4}.Inspect());
        }
 
[TestMethod]
        public void ShouldNotRecurseIntoItemsInList()
        {
            var list = new List<object>();
            list.Add(new List<string>());
            Assert.AreEqual("[[...]]", list.Inspect());
        }
 
[TestMethod]
        public void ShouldNotRecurseIntoItemsInDictionary()
        {
            var dictionary = new Dictionary<string, object>();
            dictionary["test"] = new Dictionary<string, int>();
            AssertMatch("{\"test\" => {...}}",
                        dictionary.Inspect());
        }
 
        public class TestClass
        {
            public object Thing { get; set; }
            internal object InternalThing { get; set; }
            protected object ProtectedThing { get; set; }
            private object PrivateThing { get; set; }
        }
 
[TestMethod]
        public void ShouldNotRecurseIntoItemsInObject()
        {
            var x = new TestClass();
            x.Thing = new TestClass();
            Assert.AreEqual(
                "#<SEP.Extensions.Tests.InspectExtensionTests+TestClass Thing=#<SEP.Extensions.Tests.InspectExtensionTests+TestClass:0x11a2ccb>>",
                x.Inspect());
        }
 
        public class TestGenericClass<T>
        {
        }
 
[TestMethod]
        public void ShouldReportGenericTypes()
        {
            Assert.AreEqual("#<SEP.Extensions.Tests.InspectExtensionTests+TestGenericClass<System.Int32>>",
                            new TestGenericClass<int>().Inspect());
        }
 
        public class TestInspectableClass
        {
            public string Inspect()
            {
                return "inspection!";
            }
        }
 
[TestMethod]
        public void ShouldInspectInspectable()
        {
            Assert.AreEqual("inspection!", new TestInspectableClass().Inspect());
        }
 
[TestMethod]
        public void ShouldInspectInspectableInList()
        {
            var list = new List<object>();
            list.Add(new TestInspectableClass());
            Assert.AreEqual("[inspection!]", list.Inspect());
        }
 
[Flags]
        public enum TestEnum
        {
            A = 0x01,
            B = 0x02,
            C = 0x04
        }
 
[TestMethod]
        public void ShouldInspectEnum()
        {
            Assert.AreEqual("A|B", (TestEnum.A | TestEnum.B).Inspect());
        }
 
 
 
        private void AssertMatch(string expectedPattern, string actual)
        {
            AssertMatch(new Regex(expectedPattern), actual);
        }
 
        private void AssertMatch(Regex expectedRegex, string actual)
        {
            Assert.IsTrue(expectedRegex.IsMatch(actual), "Expected to match: <" + expectedRegex + "> but was <" + actual + ">");
        }
    }
}