1.1 --- a/vRecurrence.py Sat Oct 04 01:07:46 2014 +0200
1.2 +++ b/vRecurrence.py Sat Oct 04 16:04:55 2014 +0200
1.3 @@ -78,8 +78,6 @@
1.4 ("BYMONTH",)
1.5 )
1.6
1.7 -special_enum_levels = ("BYDAY", "BYMONTHDAY", "BYYEARDAY")
1.8 -
1.9 # Map from levels to lengths of datetime tuples.
1.10
1.11 lengths = [6, 5, 4, 3, 3, 2, 1]
1.12 @@ -118,9 +116,9 @@
1.13 for qualifier, args in qualifiers:
1.14 if enum.has_key(qualifier):
1.15 level = enum[qualifier]
1.16 - if qualifier in special_enum_levels:
1.17 + if special_enum_levels.has_key(qualifier):
1.18 args["interval"] = 1
1.19 - selector = PatternFilter
1.20 + selector = special_enum_levels[qualifier]
1.21 else:
1.22 selector = Enum
1.23 else:
1.24 @@ -295,23 +293,22 @@
1.25 def __repr__(self):
1.26 return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.pos, self.args, self.qualifier, self.context)
1.27
1.28 - def materialise(self, end, count=None):
1.29 + def materialise(self, start, end, count=None):
1.30 counter = count and [0, count]
1.31 - return self.materialise_items(self.context, end, counter)
1.32 + return self.materialise_items(self.context, start, end, counter)
1.33
1.34 - def materialise_item(self, current, next, counter):
1.35 + def materialise_item(self, current, last, next, counter):
1.36 if counter is None or counter[0] < counter[1]:
1.37 if self.selecting:
1.38 - return self.selecting.materialise_items(current, next, counter)
1.39 - else:
1.40 + return self.selecting.materialise_items(current, last, next, counter)
1.41 + elif last <= current:
1.42 if counter is not None:
1.43 counter[0] += 1
1.44 return [current]
1.45 - else:
1.46 - return []
1.47 + return []
1.48
1.49 class Pattern(Selector):
1.50 - def materialise_items(self, context, end, counter):
1.51 + def materialise_items(self, context, start, end, counter):
1.52 first = scale(self.args["values"][0], self.pos)
1.53
1.54 # Define the step between items.
1.55 @@ -330,13 +327,13 @@
1.56 while current < end and (counter is None or counter[0] < counter[1]):
1.57 next = update(current, step)
1.58 current_end = update(current, unit_step)
1.59 - results += self.materialise_item(current, min(current_end, end), counter)
1.60 + results += self.materialise_item(current, max(current, start), min(current_end, end), counter)
1.61 current = next
1.62
1.63 return results
1.64
1.65 -class PatternFilter(Selector):
1.66 - def materialise_items(self, context, end, counter):
1.67 +class WeekDayFilter(Selector):
1.68 + def materialise_items(self, context, start, end, counter):
1.69 first = scale(bases[self.pos], self.pos)
1.70
1.71 # Define the step between items to be tested.
1.72 @@ -348,36 +345,49 @@
1.73
1.74 while current < end and (counter is None or counter[0] < counter[1]):
1.75 next = update(current, step)
1.76 - results += self.materialise_item(current, min(next, end), counter)
1.77 + results += self.materialise_item(current, max(current, start), min(next, end), counter)
1.78 current = next
1.79
1.80 return results
1.81
1.82 - def materialise_item(self, current, next, counter):
1.83 + def materialise_item(self, current, last, next, counter):
1.84 values = self.args["values"]
1.85
1.86 # Select by day in week, also by occurrence in month.
1.87
1.88 - if self.qualifier == "BYDAY":
1.89 - for value, index in values:
1.90 - if datetime(*current).isoweekday() == value:
1.91 - last_day = monthrange(current[0], current[1])[1]
1.92 - index_from_start = (current[2] - 1) / 7
1.93 - index_from_end = -(1 + (last_day - current[2]) / 7)
1.94 - if index is None or index in (index_from_start, index_from_end):
1.95 - return Selector.materialise_item(self, current, next, counter)
1.96 + for value, index in values:
1.97 + if datetime(*current).isoweekday() == value:
1.98 + last_day = monthrange(current[0], current[1])[1]
1.99 + index_from_start = (current[2] - 1) / 7
1.100 + index_from_end = -(1 + (last_day - current[2]) / 7)
1.101 + if index is None or index in (index_from_start, index_from_end):
1.102 + return Selector.materialise_item(self, current, last, next, counter)
1.103
1.104 return []
1.105
1.106 class Enum(Selector):
1.107 - def materialise_items(self, context, end, counter):
1.108 + def materialise_items(self, context, start, end, counter):
1.109 step = scale(1, self.pos)
1.110 results = []
1.111 for value in self.args["values"]:
1.112 current = combine(context, scale(value, self.pos))
1.113 if current < end and (counter is None or counter[0] < counter[1]):
1.114 next = update(current, step)
1.115 - results += self.materialise_item(current, min(next, end), counter)
1.116 + results += self.materialise_item(current, max(current, start), min(next, end), counter)
1.117 + return results
1.118 +
1.119 +class MonthDayFilter(Enum):
1.120 + def materialise_items(self, context, start, end, counter):
1.121 + last_day = monthrange(context[0], context[1])[1]
1.122 + step = scale(1, self.pos)
1.123 + results = []
1.124 + for value in self.args["values"]:
1.125 + if value < 0:
1.126 + value = last_day + 1 + value
1.127 + current = combine(context, scale(value, self.pos))
1.128 + if current < end and (counter is None or counter[0] < counter[1]):
1.129 + next = update(current, step)
1.130 + results += self.materialise_item(current, max(current, start), min(next, end), counter)
1.131 return results
1.132
1.133 def process(selectors):
1.134 @@ -387,4 +397,10 @@
1.135 current = selector
1.136 return selectors[0]
1.137
1.138 +special_enum_levels = {
1.139 + "BYDAY" : WeekDayFilter,
1.140 + "BYMONTHDAY" : MonthDayFilter,
1.141 + #"BYYEARDAY" : YearDayFilter,
1.142 + }
1.143 +
1.144 # vim: tabstop=4 expandtab shiftwidth=4