icalPal 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4dab143a05d8a63ae36b721ca6ba53180c75d8b4dd0f0cebdc84fb533968c248
4
- data.tar.gz: 8d243a120762c90059e4206a2deb5e79b821e558cf9ad9a437ad84fbfbb6a21b
3
+ metadata.gz: 76513daaf66f3c4aa8b2a9e1703f275ba5d5a65ef9e8b71a86b263c59d409fdd
4
+ data.tar.gz: c06430cfbdd5c415dae2d154b774c1ba1feb210534e6511f9fbb1cf12052cbfd
5
5
  SHA512:
6
- metadata.gz: 24f4b88c592e59f2ffbc116761d6da41b60a7e5d4554feea9bdb023450967eaa7921f5c4708a66bf76554926ab4e0ca52965470f7576cef1cce5aec9a6112cbb
7
- data.tar.gz: d69cc1d2cd63072020a4059a352ccdb2262a189e10c3c4e1891bd1c953ea2cb60a577fc83bd2ab55b561d0a752b0fb4198495bc2a5f57909d4216101cc7ea012
6
+ metadata.gz: 290f75e744ea88673f474c478565ec281a2b8eae8dcfc730ccb7abf88f33b5fdc8c10baf53b971c336d48a3a4abc3f311e02973e9f2295fea2d134e3d987a499
7
+ data.tar.gz: af3d7eec48d408f2c7ff15af7cdddcf581fa60574e1ab3602efb32e6625bfa61833919194108fe012fbae35a312c14af6ffbf628be4921d7cd11651e67717151
data/bin/icalPal CHANGED
@@ -130,6 +130,18 @@ $rows.each_with_index do |row, i|
130
130
  next
131
131
  end
132
132
 
133
+ # --regexp
134
+ if $opts[:match]
135
+ r = $opts[:match].split('=')
136
+
137
+ if item[r[0]].to_s.respond_to?(:match)
138
+ unless item[r[0]].to_s.match(Regexp.new(r[1].to_s, Regexp::IGNORECASE)) then
139
+ $log.debug(":regex")
140
+ next
141
+ end
142
+ end
143
+ end
144
+
133
145
  if ICalPal::Event === item
134
146
  # Check for all-day and cancelled events
135
147
  if $opts[:ea] && item['all_day'].positive? then
data/lib/defaults.rb CHANGED
@@ -26,6 +26,7 @@ $defaults = {
26
26
  output: 'default',
27
27
  ps: [ "\n " ],
28
28
  r: false,
29
+ match: nil,
29
30
  sc: false,
30
31
  sd: false,
31
32
  sep: false,
data/lib/event.rb CHANGED
@@ -110,20 +110,22 @@ module ICalPal
110
110
  # If an event spans multiple days, the return value will contain
111
111
  # a unique {Event} for each day that falls within our window
112
112
  def non_recurring
113
- retval = []
113
+ events = []
114
114
 
115
115
  # Repeat for multi-day events
116
116
  ((self['duration'] / 86400).to_i + 1).times do |i|
117
117
  break if self['sdate'] > $opts[:to]
118
118
 
119
119
  $log.debug("multi-day event #{i + 1}") if (i > 0)
120
+
120
121
  self['daynum'] = i + 1
121
- retval.push(clone) if in_window?(self['sdate'])
122
+ events.push(clone) if in_window?(self['sdate'])
123
+
122
124
  self['sdate'] += 1
123
125
  self['edate'] += 1
124
126
  end
125
127
 
126
- retval
128
+ events
127
129
  end
128
130
 
129
131
  # Check recurring events
@@ -131,35 +133,49 @@ module ICalPal
131
133
  # @return [Array<Event>]
132
134
  # All occurrences of a recurring event that are within our window
133
135
  def recurring
134
- retval = []
136
+ stop = [ $opts[:to], (self['rdate'] || $opts[:to]) ].min
135
137
 
136
138
  # See if event ends before we start
137
- stop = [ $opts[:to], (self['rdate'] || $opts[:to]) ].min
138
139
  if stop < $opts[:from] then
139
140
  $log.debug("#{stop} < #{$opts[:from]}")
140
- return(retval)
141
+ return(Array.new)
141
142
  end
142
143
 
143
144
  # Get changes to series
144
- changes = $rows.select { |r| r['orig_item_id'] == self['ROWID'] }
145
+ changes = [ { 'orig_date' => -1 } ]
146
+ changes += $rows.select { |r| r['orig_item_id'] == self['ROWID'] }
147
+
148
+ events = []
149
+ count = 1
145
150
 
146
- i = 1
147
151
  while self['sdate'] <= stop
148
- if self['count'].positive? && i > self['count'] then
149
- $log.debug("count exceeded: #{i} > #{self['count']}")
150
- return(retval)
152
+ # count
153
+ break if self['count'].positive? and count > self['count']
154
+ count += 1
155
+
156
+ # Handle specifier or clone self
157
+ if self['specifier'] and self['specifier'].length.positive?
158
+ occurrences = get_occurrences(changes)
159
+ else
160
+ occurrences = [ clone ]
151
161
  end
152
- i += 1
153
162
 
154
- unless @self['xdate'].any?(@self['sdate']) # Exceptions?
155
- o = get_occurrences(changes)
156
- o.each { |r| retval.push(r) if in_window?(r['sdate'], r['edate']) }
163
+ # Check for changes
164
+ occurrences.each do |occurrence|
165
+ changes.each do |change|
166
+ next if change['orig_date'] == self['sdate'].to_i - ITIME
167
+ events.push(occurrence) if in_window?(occurrence['sdate'], occurrence['edate'])
168
+ end
157
169
  end
158
170
 
171
+ break if self['specifier']
159
172
  apply_frequency!
160
173
  end
161
174
 
162
- retval
175
+ # Remove exceptions
176
+ events.delete_if { |event| event['xdate'].any?(event['sdate']) }
177
+
178
+ return(events)
163
179
  end
164
180
 
165
181
  private
@@ -168,67 +184,72 @@ module ICalPal
168
184
 
169
185
  # @return a deep clone of self
170
186
  def clone()
171
- self['stime'] = @self['sdate'].to_i
172
- self['etime'] = @self['edate'].to_i
173
-
174
187
  Marshal.load(Marshal.dump(self))
175
188
  end
176
189
 
177
- # Get next occurences of a recurring event
190
+ # Get next occurences of a recurring event from a specifier
178
191
  #
179
192
  # @param changes [Array] Recurrence changes for the event
180
193
  # @return [Array<IcalPal::Event>]
181
194
  def get_occurrences(changes)
182
- ndate = self['sdate']
183
- odays = []
184
- retval = []
185
-
186
- # Deconstruct specifier(s)
187
- if self['specifier']
188
- self['specifier'].split(';').each do |k|
189
- j = k.split('=')
190
-
191
- # M=Day of the month, O=Month of the year, S=Nth
192
- case j[0]
193
- when 'M' then ndate = RDT.new(ndate.year, ndate.month, j[1].to_i)
194
- when 'O' then ndate = RDT.new(ndate.year, j[1].to_i, ndate.day)
195
- when 'S' then @self['specifier'].sub!(/D=0/, "D=+#{j[1].to_i}")
196
- end
197
-
198
- # No time travel!
199
- ndate = self['sdate'] if ndate <= self['sdate']
195
+ occurrences = []
196
+
197
+ dow = DOW.keys
198
+ dom = [ nil ]
199
+ moy = 1..12
200
+ nth = nil
201
+
202
+ specifier = self['specifier']? self['specifier'] : []
203
+
204
+ # Deconstruct specifier
205
+ specifier.split(';').each do |k|
206
+ j = k.split('=')
207
+
208
+ # D=Day of the week, M=Day of the month, O=Month of the year, S=Nth
209
+ case j[0]
210
+ when 'D' then dow = j[1].split(',')
211
+ when 'M' then dom = j[1].split(',')
212
+ when 'O' then moy = j[1].split(',')
213
+ when 'S' then nth = j[1].to_i
214
+ else $log.warn("Unknown specifier: #{k}")
200
215
  end
216
+ end
201
217
 
202
- # D=Day of the week
203
- self['specifier'].split(';').each do |k|
204
- j = k.split('=')
218
+ # Build array of DOWs
219
+ dows = [ nil ]
220
+ dow.each { |d| dows.push(DOW[d[-2..-1].to_sym]) }
205
221
 
206
- odays = j[1].split(',') if j[0] == 'D'
207
- end
208
- end
222
+ # Months of the year (O)
223
+ moy.each do |m|
224
+ next unless m
209
225
 
210
- # Deconstruct occurence day(s)
211
- odays.each do |n|
212
- dow = DOW[n[-2..-1].to_sym]
213
- ndate += 1 until ndate.wday == dow
214
- ndate = ICalPal.nth(Integer(n[0..1]), n[-2..-1], ndate) unless (n[0] == '0')
226
+ nsdate = RDT.new(self['sdate'].year, m.to_i, 1)
227
+ nedate = RDT.new(self['edate'].year, m.to_i, 1)
215
228
 
216
- # Check for changes
217
- changes.detect(
218
- proc {
219
- self['sdate'] = RDT.new(*ndate.to_a[0..2], *self['sdate'].to_a[3..])
220
- self['edate'] = RDT.new(*ndate.to_a[0..2], *self['edate'].to_a[3..])
221
- retval.push(clone)
222
- }) { |i| @self['sday'] == i['sday'] }
223
- end
229
+ # Days of the month (M)
230
+ dom.each do |x|
231
+ next unless x
224
232
 
225
- # Check for changes
226
- changes.detect(
227
- proc {
228
- retval.push(clone)
229
- }) { |i| @self['sday'] == i['sday'] } unless retval.count.positive?
233
+ self['sdate'] = RDT.new(nsdate.year, nsdate.month, x.to_i)
234
+ self['edate'] = RDT.new(nedate.year, nedate.month, x.to_i)
235
+ occurrences.push(clone)
236
+ end
237
+
238
+ # Days of the week (D)
239
+ if nth
240
+ self['sdate'] = ICalPal.nth(nth, dows, nsdate)
241
+ self['edate'] = ICalPal.nth(nth, dows, nedate)
242
+ occurrences.push(clone)
243
+ else
244
+ if dows[0]
245
+ self['sdate'] = RDT.new(nsdate.year, m.to_i, nsdate.wday)
246
+ self['edate'] = RDT.new(nedate.year, m.to_i, nedate.wday)
247
+ occurrences.push(clone)
248
+ end
249
+ end
250
+ end
230
251
 
231
- retval
252
+ return(occurrences)
232
253
  end
233
254
 
234
255
  # Apply frequency and interval
@@ -243,6 +264,7 @@ module ICalPal
243
264
  when 'weekly' then self[d] += self['interval'] * 7
244
265
  when 'monthly' then self[d] >>= self['interval']
245
266
  when 'yearly' then self[d] >>= self['interval'] * 12
267
+ else $log.error("Unknown frequency: #{self['frequency']}")
246
268
  end
247
269
  end if self['frequency'] && self['interval']
248
270
  end
data/lib/icalPal.rb CHANGED
@@ -141,7 +141,7 @@ module ICalPal
141
141
  # Get the +n+'th +dow+ in month +m+
142
142
  #
143
143
  # @param n [Integer] Integer between -4 and +4
144
- # @param dow [String] Day of the week abbreviation from ICalPal::DOW
144
+ # @param dow [Array] Days of the week
145
145
  # @param m [RDT] The RDT with the year and month we're searching
146
146
  # @return [RDT] The resulting day
147
147
  def self.nth(n, dow, m)
@@ -155,7 +155,7 @@ module ICalPal
155
155
 
156
156
  j = 0
157
157
  a[0].step(a[1], step) do |i|
158
- j += step if i.wday == DOW[dow.to_sym]
158
+ j += step if dow.any?(i.wday)
159
159
  return i if j == n
160
160
  end
161
161
  end
data/lib/options.rb CHANGED
@@ -55,7 +55,7 @@ module ICalPal
55
55
  "Print as FORMAT (default: #{$defaults[:common][:output]})", "[#{OUTFORMATS.join(', ')}]")
56
56
 
57
57
  # include/exclude
58
- @op.separator("\nIncluding/excluding calendars:\n\n")
58
+ @op.separator("\nIncluding/excluding accounts, calendars, items:\n\n")
59
59
 
60
60
  @op.on('--is=ACCOUNTS', Array, 'List of accounts to include')
61
61
  @op.on('--es=ACCOUNTS', Array, 'List of accounts to exclude')
@@ -73,6 +73,9 @@ module ICalPal
73
73
  @op.on('--il=LISTS', Array, 'List of reminder lists to include')
74
74
  @op.on('--el=LISTS', Array, 'List of reminder lists to exclude')
75
75
 
76
+ @op.separator('')
77
+ @op.on('--match=FIELD=REGEXP', String, 'Include only items whose FIELD matches REGEXP (ignoring case)')
78
+
76
79
  # dates
77
80
  @op.separator("\nChoosing dates:\n\n")
78
81
 
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ICalPal
2
- VERSION = '2.1.0'
2
+ VERSION = '2.2.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: icalPal
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Rosen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-28 00:00:00.000000000 Z
11
+ date: 2024-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sqlite3