OLD | NEW |
---|---|
(Empty) | |
1 /** | |
Emily Fortuna
2012/08/06 22:43:00
copyright notice at top
Alan Knight
2012/08/08 00:47:44
Oops. Done.
| |
2 * A class for holding onto the data for a date so that it can be built | |
3 * up incrementally. | |
4 */ | |
5 class _DateBuilder { | |
6 int year = 0, | |
7 month = 0, | |
8 day = 0, | |
9 hour = 0, | |
10 minute = 0, | |
11 second = 0, | |
12 fractionalSecond = 0; | |
13 bool pm = false; | |
14 bool utc = false; | |
15 | |
16 // Functions that exist just be closurized so we can pass them to a general | |
Emily Fortuna
2012/08/06 22:43:00
missing word in here "exist just be closurized"
Alan Knight
2012/08/08 00:47:44
Done.
| |
17 // method. | |
18 void setYear(x) { year = x; } | |
19 void setMonth(x) { month = x; } | |
20 void setDay(x) { day = x; } | |
21 void setHour(x) { hour = x; } | |
22 void setMinute(x) { minute = x; } | |
23 void setSecond(x) { second = x; } | |
24 void setFractionalSecond(x) { fractionalSecond = x; } | |
25 | |
26 /** | |
27 * Return a date built using our values. If no date portion is set, | |
28 * use today's date, as otherwise the constructor will fail. | |
29 */ | |
30 Date asDate() { | |
31 if (year == 0 || month == 0 || day == 0) { | |
32 var today = new Date.now(); | |
33 if (year == 0) year = today.year; | |
34 if (month == 0) month = today.month; | |
35 if (day == 0) day = today.day; | |
36 } | |
37 | |
38 // TODO(alanknight): Validate the date, especially for things which | |
39 // can crash the VM, e.g. large month values. | |
40 return new Date( | |
41 year, | |
Emily Fortuna
2012/08/06 22:43:00
indent 4 spaces here
Alan Knight
2012/08/08 00:47:44
Done.
| |
42 month, | |
43 day, | |
44 pm ? hour + 12 : hour, | |
45 minute, | |
46 second, | |
47 fractionalSecond, | |
48 utc); | |
49 } | |
50 } | |
51 | |
52 /** | |
53 * A simple and not particularly general stream class to make parsing | |
54 * dates from strings simpler. It is general enough to operate on either | |
55 * lists or strings. | |
56 */ | |
57 class _Stream { | |
58 var contents; | |
59 int index = 0; | |
60 | |
61 _Stream(this.contents); | |
62 | |
63 bool atEnd() => index >= contents.length; | |
64 | |
65 Dynamic next() => contents[index++]; | |
66 | |
67 /** | |
68 * Return the next [howMany] items, or as many as there are remaining. | |
69 * Advance the stream by that many positions. | |
70 */ | |
71 read([howMany = 1]) { | |
72 var result = peek(howMany); | |
73 index += howMany; | |
74 return result; | |
75 } | |
76 | |
77 /** | |
78 * Return the next [howMany] items, or as many as there are remaining. | |
79 * Does not modify the stream position. | |
80 */ | |
81 peek([howMany = 1]) { | |
82 var result; | |
83 if (contents is String) { | |
84 result = contents.substring( | |
85 index, | |
Emily Fortuna
2012/08/06 22:43:00
4 spaces indent if it's after an opening (
Alan Knight
2012/08/08 00:47:44
Done.
| |
86 Math.min(index + howMany, contents.length)); | |
87 } else { | |
88 // Assume List | |
89 result = contents.getRange(index,howMany); | |
90 } | |
91 return result; | |
92 } | |
93 | |
94 /** Return the remaining contents of the stream */ | |
95 rest() => peek(contents.length - index); | |
96 | |
97 /** Find the index of the first element for which [f] returns true.*/ | |
Emily Fortuna
2012/08/06 22:43:00
mention this has the side effect of advancing the
Alan Knight
2012/08/08 00:47:44
Done.
| |
98 int findIndex(Function f) { | |
99 while (!atEnd()) { | |
100 if (f(next())) return index - 1; | |
101 } | |
102 return null; | |
103 } | |
104 | |
105 /** | |
106 * Find the indexes of all the elements for which [f] returns true. | |
107 * Also leaves the stream positioned at the end. | |
108 */ | |
109 List findIndexes(Function f) { | |
110 var results = []; | |
111 while (!atEnd()) { | |
112 if (f(next())) results.add(index - 1); | |
113 } | |
114 return results; | |
115 } | |
116 | |
117 /** | |
118 * Assuming that the contents are characters, read as many digits as we | |
119 * can see and then return the corresponding integer. Advance the stream. | |
120 */ | |
121 int nextInteger() { | |
122 var validDigits = '0123456789'; | |
123 var digits = []; | |
124 while (!atEnd() && (validDigits.contains(peek()))) { | |
125 digits.add(next().charCodeAt(0)); | |
126 } | |
127 return Math.parseInt(new String.fromCharCodes(digits)); | |
128 } | |
129 } | |
130 | |
131 /** | |
132 * Exception indicating that we could not parse a particular string into a | |
133 * Date according to the specified pattern. | |
134 */ | |
135 class FormatException implements Exception { | |
Emily Fortuna
2012/08/06 22:43:00
We now have a FormatException as a subclass of the
Alan Knight
2012/08/08 00:47:44
Done.
| |
136 final _Stream input; | |
137 final _DateFormatField field; | |
138 | |
139 const FormatException(this.input, this.field); | |
140 | |
141 toString() => "FormatException: $field matching ${input.rest}"; | |
142 } | |
OLD | NEW |