icalPal 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/icalPal +86 -27
- data/icalPal.gemspec +1 -1
- data/lib/event.rb +40 -10
- data/lib/icalPal.rb +12 -0
- data/lib/options.rb +1 -1
- data/lib/rdt.rb +7 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c08ab4aaf0558f9648fbefbb9eaea1aac9c50de2770e1897699b619ba92ef6b6
|
4
|
+
data.tar.gz: '087d14b6e855bdbf2681e526941baec600fed607a6e6760b09f4361bb33735d8'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70934664b432d1b99e0f200bd1e78a2b142f9b1b9b405c8763913aa9d414a83171f4876e0145ff741854abd1b643fdb4a72031b564af14a2a4f1764cc494a13f
|
7
|
+
data.tar.gz: '0580e0d9556919516b1c2d4a4ea11306a2a8786ea80ee5ccc5821c97f899d7bc95c3499c7f5d9dc05ac091dba53867b01a7b676e0bd20881563d7529e16a1a31'
|
data/bin/icalPal
CHANGED
@@ -59,45 +59,91 @@ q = klass::QUERY
|
|
59
59
|
$log.debug(q.gsub(/\n/, ' '))
|
60
60
|
|
61
61
|
# Get it
|
62
|
-
|
63
|
-
|
64
|
-
|
62
|
+
begin
|
63
|
+
stmt = $db.prepare(q)
|
64
|
+
abort(stmt.columns.sort.join(' ')) if $opts[:props].any? 'list'
|
65
|
+
$opts[:props] = stmt.columns - $opts[:eep] if $opts[:props].any? 'all'
|
66
|
+
|
67
|
+
# Iterate the SQLite3::ResultSet once
|
68
|
+
stmt.execute.each_with_index { |i, j| $rows[j] = i }
|
69
|
+
stmt.close
|
65
70
|
|
66
|
-
#
|
67
|
-
|
68
|
-
|
71
|
+
# Close the database
|
72
|
+
$db.close
|
73
|
+
$log.debug("Closed #{$opts[:db]}")
|
69
74
|
|
70
|
-
|
71
|
-
$db.
|
75
|
+
rescue SQLite3::BusyException => e
|
76
|
+
$log.error("Non-fatal error closing database #{$db.filename}")
|
77
|
+
|
78
|
+
rescue SQLite3::SQLException => e
|
79
|
+
abort(e.message)
|
80
|
+
end
|
81
|
+
|
82
|
+
$log.info("Loaded #{$rows.count} rows from #{$opts[:db]}")
|
72
83
|
|
73
84
|
|
74
85
|
##################################################
|
75
86
|
# Process the data
|
76
87
|
|
77
88
|
# Add rows
|
78
|
-
$rows.
|
89
|
+
$rows.each_with_index do |row, i|
|
90
|
+
$log.debug("Row #{i}: #{row['ROWID']}:#{row['UUID']} - #{row['account']}/#{row['calendar']}/#{row['title']}")
|
91
|
+
|
79
92
|
# --es/--is
|
80
|
-
|
81
|
-
|
93
|
+
if $opts[:es].any? row['account'] then
|
94
|
+
$log.debug(":es")
|
95
|
+
next
|
96
|
+
end
|
97
|
+
|
98
|
+
unless $opts[:is].empty? or $opts[:is].any? row['account']
|
99
|
+
$log.debug(":is");
|
100
|
+
next
|
101
|
+
end
|
82
102
|
|
83
103
|
# --ec/--ic
|
84
|
-
|
85
|
-
|
104
|
+
if $opts[:ec].any? row['calendar'] then
|
105
|
+
$log.debug(":ec")
|
106
|
+
next
|
107
|
+
end
|
108
|
+
|
109
|
+
unless $opts[:ic].empty? or $opts[:ic].any? row['calendar']
|
110
|
+
$log.debug(":ic")
|
111
|
+
next
|
112
|
+
end
|
86
113
|
|
87
114
|
item = klass.new(row)
|
88
115
|
|
89
116
|
# --et/--it
|
90
|
-
|
91
|
-
|
117
|
+
if $opts[:et].any? item['type'] then
|
118
|
+
$log.debug(":et")
|
119
|
+
next
|
120
|
+
end
|
121
|
+
|
122
|
+
unless $opts[:it].empty? or $opts[:it].any? item['type']
|
123
|
+
$log.debug(":it")
|
124
|
+
next
|
125
|
+
end
|
92
126
|
|
93
127
|
unless ICalPal::Event === item
|
94
128
|
# Always add non-event items
|
129
|
+
$log.debug("Adding non-event #{item}")
|
95
130
|
add(item)
|
96
131
|
else
|
97
132
|
# Check for all-day and cancelled events
|
98
|
-
|
99
|
-
|
100
|
-
|
133
|
+
if $opts[:ea] && item['all_day'].positive? then
|
134
|
+
$log.debug(":ea")
|
135
|
+
next
|
136
|
+
end
|
137
|
+
|
138
|
+
if $opts[:ia] && !item['all_day'].positive? then
|
139
|
+
$log.debug(":ia")
|
140
|
+
next
|
141
|
+
end
|
142
|
+
|
143
|
+
if item['status'] == :canceled then
|
144
|
+
$log.debug(":canceled")
|
145
|
+
next
|
146
|
+
end
|
101
147
|
|
102
148
|
(item['has_recurrences'].positive?)?
|
103
149
|
item.recurring.each { |i| add(i) } :
|
@@ -111,12 +157,14 @@ if $opts[:sed] && $opts[:sd] && klass == ICalPal::Event
|
|
111
157
|
|
112
158
|
$opts[:days].times do |n|
|
113
159
|
day = $opts[:from] + n
|
114
|
-
$items.push(klass.new(day)) unless days.any? { |i| i == day }
|
160
|
+
$items.push(klass.new(day)) unless days.any? { |i| i.to_s == day.to_s }
|
115
161
|
end
|
116
162
|
end
|
117
163
|
|
118
164
|
# Sort the rows
|
119
165
|
begin
|
166
|
+
$log.debug("Sorting/uniqing #{$items.count} items by #{[ $opts[:sep], $opts[:sort], 'sdate' ]}, reverse #{$opts[:reverse].inspect}")
|
167
|
+
|
120
168
|
$items.sort_by! { |i| [ i[$opts[:sep]], i[$opts[:sort]], i['sdate'] ] }
|
121
169
|
$items.reverse! if $opts[:reverse]
|
122
170
|
$items.uniq!
|
@@ -124,6 +172,8 @@ rescue ArgumentError => e
|
|
124
172
|
$log.warn("Sorting failed, results may be unexpected\n")
|
125
173
|
end
|
126
174
|
|
175
|
+
$log.debug("#{$items.count} items remain")
|
176
|
+
|
127
177
|
# Configure formatting
|
128
178
|
mu = case $opts[:output]
|
129
179
|
when 'ansi' then RDoc::Markup::ToAnsi.new
|
@@ -145,15 +195,20 @@ mu = case $opts[:output]
|
|
145
195
|
items = $items[0..$opts[:li] - 1]
|
146
196
|
|
147
197
|
unless mu
|
198
|
+
$log.debug("Output in #{$opts[:output]} format")
|
199
|
+
|
148
200
|
puts case $opts[:output]
|
149
201
|
when 'csv' then
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
}
|
202
|
+
# Get all headers
|
203
|
+
headers = []
|
204
|
+
items.each { |i| headers += i.keys }
|
205
|
+
headers.uniq!
|
155
206
|
|
156
|
-
|
207
|
+
# Populate a CSV::Table
|
208
|
+
table = CSV::Table.new([], headers: headers)
|
209
|
+
items.each { |i| table << i.to_csv(headers) }
|
210
|
+
|
211
|
+
table
|
157
212
|
when 'hash' then items.map { |i| i.self }
|
158
213
|
when 'json' then items.map { |i| i.self }.to_json
|
159
214
|
when 'yaml' then items.map { |i| i.self }.to_yaml
|
@@ -168,9 +223,13 @@ unless mu
|
|
168
223
|
exit
|
169
224
|
end
|
170
225
|
|
226
|
+
$log.debug("Formatting with #{mu.inspect}")
|
227
|
+
|
171
228
|
section = nil if $opts[:sep]
|
172
229
|
|
173
230
|
items.each_with_index do |i, j|
|
231
|
+
$log.debug("Print #{j}: #{i.inspect}")
|
232
|
+
|
174
233
|
# --li
|
175
234
|
break if $opts[:li].positive? && j >= $opts[:li]
|
176
235
|
|
@@ -178,7 +237,7 @@ items.each_with_index do |i, j|
|
|
178
237
|
|
179
238
|
# Sections
|
180
239
|
if $opts[:sep] && section != i[$opts[:sep]]
|
181
|
-
$log.debug("
|
240
|
+
$log.debug("New section '#{$opts[:sep]}': #{i[$opts[:sep]]}")
|
182
241
|
|
183
242
|
v = RDoc::Markup::Verbatim.new
|
184
243
|
v.format = { item: i, prop: $opts[:sep] }
|
@@ -210,7 +269,7 @@ items.each_with_index do |i, j|
|
|
210
269
|
props << RDoc::Markup::Heading.new(2, i[prop].to_s)
|
211
270
|
else
|
212
271
|
props << RDoc::Markup::BlankLine.new unless (i['placeholder'] || $opts[:ps])
|
213
|
-
props << RDoc::Markup::ListItem.new(prop, RDoc::Markup::Paragraph.new(i[prop]))
|
272
|
+
props << RDoc::Markup::ListItem.new(prop, RDoc::Markup::Paragraph.new(i[prop])) unless(i['placeholder'])
|
214
273
|
end
|
215
274
|
end
|
216
275
|
|
data/icalPal.gemspec
CHANGED
data/lib/event.rb
CHANGED
@@ -3,6 +3,11 @@ module ICalPal
|
|
3
3
|
class Event
|
4
4
|
include ICalPal
|
5
5
|
|
6
|
+
# Standard accessor with special handling for +sdate+. Setting
|
7
|
+
# +sdate+ will also set +sday+.
|
8
|
+
#
|
9
|
+
# @param k [String] Key/property name
|
10
|
+
# @param v [Object] Key/property value
|
6
11
|
def []=(k, v)
|
7
12
|
@self[k] = v
|
8
13
|
@self['sday'] = ICalPal::RDT.new(*self['sdate'].to_a[0..2]) if k == 'sdate'
|
@@ -27,7 +32,7 @@ module ICalPal
|
|
27
32
|
t += ' at ' unless @self['all_day'].positive?
|
28
33
|
end
|
29
34
|
|
30
|
-
unless @self['all_day'] && @self['all_day'].positive?
|
35
|
+
unless @self['all_day'] && @self['all_day'].positive? || @self['placeholder']
|
31
36
|
t ||= ''
|
32
37
|
t += "#{@self['sdate'].strftime($opts[:tf])}" if @self['sdate']
|
33
38
|
t += " - #{@self['edate'].strftime($opts[:tf])}" unless $opts[:eed] || !@self['edate']
|
@@ -65,10 +70,11 @@ module ICalPal
|
|
65
70
|
def initialize(obj)
|
66
71
|
# Placeholder for days with no events
|
67
72
|
return @self = {
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
73
|
+
$opts[:sep] => obj,
|
74
|
+
'sdate' => obj,
|
75
|
+
'placeholder' => true,
|
76
|
+
'title' => 'Nothing.',
|
77
|
+
} if DateTime === obj
|
72
78
|
|
73
79
|
@self = {}
|
74
80
|
obj.keys.each { |k| @self[k] = obj[k] }
|
@@ -108,6 +114,7 @@ module ICalPal
|
|
108
114
|
|
109
115
|
# Repeat for multi-day events
|
110
116
|
((self['duration'] / 86400).to_i + 1).times do |i|
|
117
|
+
$log.debug("multi-day event #{i + 1}") if (i > 0)
|
111
118
|
self['daynum'] = i + 1
|
112
119
|
retval.push(clone) if in_window?(self['sdate'])
|
113
120
|
self['sdate'] += 1
|
@@ -126,14 +133,20 @@ module ICalPal
|
|
126
133
|
|
127
134
|
# See if event ends before we start
|
128
135
|
stop = [ $opts[:to], (self['rdate'] || $opts[:to]) ].min
|
129
|
-
|
136
|
+
if stop < $opts[:from] then
|
137
|
+
$log.debug("#{stop} < #{$opts[:from]}")
|
138
|
+
return(retval)
|
139
|
+
end
|
130
140
|
|
131
141
|
# Get changes to series
|
132
142
|
changes = $rows.select { |r| r['orig_item_id'] == self['ROWID'] }
|
133
143
|
|
134
144
|
i = 1
|
135
145
|
while self['sdate'] <= stop
|
136
|
-
|
146
|
+
if self['count'].positive? && i > self['count'] then
|
147
|
+
$log.debug("count exceeded: #{i} > #{self['count']}")
|
148
|
+
return(retval)
|
149
|
+
end
|
137
150
|
i += 1
|
138
151
|
|
139
152
|
unless @self['xdate'].any?(@self['sdate']) # Exceptions?
|
@@ -179,6 +192,9 @@ module ICalPal
|
|
179
192
|
when 'O' then ndate = RDT.new(ndate.year, j[1].to_i, ndate.day)
|
180
193
|
when 'S' then @self['specifier'].sub!(/D=0/, "D=+#{j[1].to_i}")
|
181
194
|
end
|
195
|
+
|
196
|
+
# No time travel!
|
197
|
+
ndate = self['sdate'] if ndate <= self['sdate']
|
182
198
|
end
|
183
199
|
|
184
200
|
# D=Day of the week
|
@@ -236,9 +252,23 @@ module ICalPal
|
|
236
252
|
# @param e [RDT] Event end
|
237
253
|
# @return [Boolean]
|
238
254
|
def in_window?(s, e = s)
|
239
|
-
$opts[:n]
|
240
|
-
($now >= s && $now < e)
|
241
|
-
|
255
|
+
if $opts[:n] then
|
256
|
+
if ($now >= s && $now < e) then
|
257
|
+
$log.debug("now: #{s} to #{e} vs. #{$now}")
|
258
|
+
return(true)
|
259
|
+
else
|
260
|
+
$log.debug("not now: #{s} to #{e} vs. #{$now}")
|
261
|
+
return(false)
|
262
|
+
end
|
263
|
+
else
|
264
|
+
if ([ s, e ].max >= $opts[:from] && s < $opts[:to]) then
|
265
|
+
$log.debug("in window: #{s} to #{e} vs. #{$opts[:from]} to #{$opts[:to]}")
|
266
|
+
return(true)
|
267
|
+
else
|
268
|
+
$log.debug("not in window: #{s} to #{e} vs. #{$opts[:from]} to #{$opts[:to]}")
|
269
|
+
return(false)
|
270
|
+
end
|
271
|
+
end
|
242
272
|
end
|
243
273
|
|
244
274
|
QUERY = <<~SQL
|
data/lib/icalPal.rb
CHANGED
@@ -43,6 +43,18 @@ module ICalPal
|
|
43
43
|
@self = obj
|
44
44
|
end
|
45
45
|
|
46
|
+
# Create a new CSV::Row with values from +self+. Newlines are
|
47
|
+
# replaced with '\n' to ensure each Row is a single line of text.
|
48
|
+
#
|
49
|
+
# @param headers [Array] Key names used as the header row in a CSV::Table
|
50
|
+
# @return [CSV::Row] The +Store+, +Calendar+, or +CalendarItem+ as a CSV::Row
|
51
|
+
def to_csv(headers)
|
52
|
+
values = []
|
53
|
+
headers.each { |h| values.push(@self[h].respond_to?(:gsub)? @self[h].gsub(/\n/, '\n') : @self[h]) }
|
54
|
+
|
55
|
+
CSV::Row::new(headers, values)
|
56
|
+
end
|
57
|
+
|
46
58
|
# Get the +n+'th +dow+ in month +m+
|
47
59
|
#
|
48
60
|
# @param n [Integer] Integer between -4 and +4
|
data/lib/options.rb
CHANGED
data/lib/rdt.rb
CHANGED
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: 1.2.
|
4
|
+
version: 1.2.1
|
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-
|
11
|
+
date: 2024-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sqlite3
|