icalPal 3.3.0 → 3.5.0

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.
data/lib/options.rb CHANGED
@@ -1,8 +1,7 @@
1
1
  # rubocop: disable Style/FormatString, Style/FormatStringToken
2
2
 
3
- require 'optparse'
3
+ autoload(:OptionParser, 'optparse')
4
4
 
5
- require_relative 'defaults'
6
5
  require_relative 'version'
7
6
 
8
7
  module ICalPal
@@ -27,9 +26,9 @@ module ICalPal
27
26
  @op = OptionParser.new
28
27
  @op.summary_width = 23
29
28
  @op.banner += ' [-c] COMMAND'
30
- @op.version = ICalPal::VERSION
29
+ @op.version = VERSION
31
30
 
32
- @op.accept(ICalPal::RDT) { |s| ICalPal::RDT.conv(s) }
31
+ @op.accept(RDT) { |s| RDT.conv(s) }
33
32
 
34
33
  # head
35
34
  @op.on_head("\nCOMMAND must be one of the following:\n\n")
@@ -55,6 +54,7 @@ module ICalPal
55
54
  'For the tasks commands this should be a directory containing .sqlite files',
56
55
  "(default: #{$defaults[:tasks][:db]})")
57
56
  @op.on('--cf=FILE', "Set config file path (default: #{$defaults[:common][:cf]})")
57
+ @op.on('--norc', 'Ignore ICALPAL and ICALPAL_CONFIG environment variables')
58
58
  @op.on('-o', '--output=FORMAT', OUTFORMATS,
59
59
  "Print as FORMAT (default: #{$defaults[:common][:output]})", "[#{OUTFORMATS.join(', ')}]")
60
60
 
@@ -83,8 +83,8 @@ module ICalPal
83
83
  # dates
84
84
  @op.separator("\nChoosing dates:\n\n")
85
85
 
86
- @op.on('--from=DATE', ICalPal::RDT, 'List events starting on or after DATE')
87
- @op.on('--to=DATE', ICalPal::RDT, 'List events starting on or before DATE',
86
+ @op.on('--from=DATE', RDT, 'List events starting on or after DATE')
87
+ @op.on('--to=DATE', RDT, 'List events starting on or before DATE',
88
88
  'DATE can be yesterday, today, tomorrow, +N, -N, or anything accepted by DateTime.parse()',
89
89
  'See https://ruby-doc.org/stdlib-2.6.1/libdoc/date/rdoc/DateTime.html#method-c-parse')
90
90
  @op.separator('')
@@ -172,6 +172,14 @@ module ICalPal
172
172
  @op.on_tail('%s%s %sAdditional arguments' % pad('ICALPAL'))
173
173
  @op.on_tail('%s%s %sAdditional arguments from a file' % pad('ICALPAL_CONFIG'))
174
174
  @op.on_tail("%s%s %s(default: #{$defaults[:common][:cf]})" % pad(''))
175
+
176
+ @op.on_tail('')
177
+
178
+ note = 'Do not quote or escape values.'
179
+ note += ' Options set in ICALPAL override ICALPAL_CONFIG.'
180
+ note += ' Options on the command line override ICALPAL.'
181
+
182
+ @op.on_tail("#{@op.summary_indent}#{note}")
175
183
  end
176
184
 
177
185
  # Parse options from the CLI and merge them with other sources
@@ -184,11 +192,45 @@ module ICalPal
184
192
  env = {}
185
193
  cf = {}
186
194
 
187
- # Load from CLI, environment, configuration file
195
+ # Load from CLI
188
196
  @op.parse!(into: cli)
189
- @op.parse!(ENV['ICALPAL'].split, into: env) rescue nil
190
- cli[:cf] ||= ENV['ICALPAL_CONFIG'] || $defaults[:common][:cf]
191
- @op.parse!(File.read(File.expand_path(cli[:cf])).split, into: cf) rescue nil
197
+
198
+ # Environment variable needs special parsing.
199
+ # OptionParser.parse doesn't handle whitespace in a
200
+ # comma-separated value.
201
+ begin
202
+ o = []
203
+
204
+ ENV['ICALPAL'].gsub(/^-/, ' -').split(' -').each do |e|
205
+ a = e.split(' ', 2)
206
+
207
+ if a[0]
208
+ o.push("-#{a[0]}")
209
+ o.push(a[1]) if a[1]
210
+ end
211
+ end
212
+
213
+ @op.parse!(o, into: env)
214
+ end if ENV['ICALPAL'] && !cli[:norc]
215
+
216
+ # Configuration file needs special parsing for the same reason
217
+ begin
218
+ o = []
219
+
220
+ cli[:cf] ||= ENV['ICALPAL_CONFIG'] || $defaults[:common][:cf]
221
+
222
+ File.read(File.expand_path(cli[:cf])).split("\n").each do |line|
223
+ a = line.split(' ', 2)
224
+
225
+ if a[0] && a[0][0] != '#'
226
+ o.push(a[0])
227
+ o.push(a[1]) if a[1]
228
+ end
229
+ end
230
+
231
+ @op.parse!(o, into: cf)
232
+ rescue StandardError
233
+ end unless cli[:norc]
192
234
 
193
235
  cli[:cmd] ||= @op.default_argv[0]
194
236
  cli[:cmd] ||= env[:cmd] if env[:cmd]
@@ -198,10 +240,10 @@ module ICalPal
198
240
  # Parse eventsNow and eventsToday commands
199
241
  cli[:cmd].match('events(Now|Today)(\+[0-9]+)?') do |m|
200
242
  cli[:now] = true if m[1] == 'Now'
201
- cli[:days] = (m[1] == 'Today')? m[2].to_i + 1 : 1
243
+ cli[:days] = (m[1] == 'Today')? m[2].to_i : 1
202
244
 
203
245
  cli[:from] = $today
204
- cli[:to] = $today + cli[:days]
246
+ cli[:to] = $today + cli[:days] if cli[:days]
205
247
  cli[:days] = Integer(cli[:to] - cli[:from])
206
248
 
207
249
  cli[:cmd] = 'events'
@@ -244,6 +286,7 @@ module ICalPal
244
286
  opts[:to] += 1 if opts[:to]
245
287
  opts[:to] ||= opts[:from] + 1 if opts[:from]
246
288
  opts[:to] = opts[:from] + opts[:days] if opts[:days]
289
+ opts[:to] = RDT.new(*opts[:to].to_a[0..2] + [ 23, 59, 59 ])
247
290
  opts[:days] ||= Integer(opts[:to] - opts[:from])
248
291
  opts[:from] = $now if opts[:n]
249
292
  end
@@ -287,7 +330,9 @@ module ICalPal
287
330
  # Pad non-options to align with options
288
331
  #
289
332
  # @param t [String] Text on the left side
290
- # @return [String] Text indented by summary_indent, and padded according to summary_width
333
+ #
334
+ # @return [Array<String>] Array containing +summary_indent+, +t+,
335
+ # a number of spaces equal to (+summary_width+ - +t.length+)
291
336
  def pad(t)
292
337
  [ @op.summary_indent, t, ' ' * (@op.summary_width - t.length) ]
293
338
  end
data/lib/rdt.rb CHANGED
@@ -1,9 +1,22 @@
1
- require 'date'
2
-
3
1
  module ICalPal
4
2
  # Child class of DateTime that adds support for relative dates (<em><b>R</b>elative<b>D</b>ate<b>T</b>ime</em>).
5
3
  class RDT < DateTime
6
4
 
5
+ # Create a new RDT from a Time object
6
+ def self.from_time(t)
7
+ new(*t.to_a[0..5].reverse)
8
+ end
9
+
10
+ # Create a new RDT from seconds since epoch
11
+ def self.from_epoch(s)
12
+ from_time(Time.at(s))
13
+ end
14
+
15
+ # Create a new RDT from seconds since iCal epoch
16
+ def self.from_itime(s)
17
+ from_epoch(s + ITIME)
18
+ end
19
+
7
20
  # Convert a String to an RDT
8
21
  #
9
22
  # @param str [String] can be +yesterday+, +today+, +tomorrow+,
@@ -28,7 +41,7 @@ module ICalPal
28
41
  # @return [String] A string representation of self relative to
29
42
  # today.
30
43
  def to_s
31
- return strftime($opts[:df]) if $opts[:nrd] && $opts[:df]
44
+ return strftime($opts[:df]) if $opts && $opts[:nrd] && $opts[:df]
32
45
 
33
46
  case Integer(RDT.new(year, month, day) - $today)
34
47
  when -2 then 'day before yesterday'
@@ -36,7 +49,7 @@ module ICalPal
36
49
  when 0 then 'today'
37
50
  when 1 then 'tomorrow'
38
51
  when 2 then 'day after tomorrow'
39
- else strftime($opts[:df]) if $opts[:df]
52
+ else strftime($opts[:df]) if $opts && $opts[:df]
40
53
  end
41
54
  end
42
55
 
@@ -54,6 +67,11 @@ module ICalPal
54
67
  to_time.to_i
55
68
  end
56
69
 
70
+ # @return [Array] Only the year, month and day of self
71
+ def ymd
72
+ [ year, month, day ]
73
+ end
74
+
57
75
  # @see ICalPal::RDT.to_s
58
76
  #
59
77
  # @return [Boolean]
data/lib/utils.rb CHANGED
@@ -9,10 +9,6 @@ def xmlify(key, value)
9
9
  # Nil
10
10
  when NilClass then "<#{key}/>"
11
11
 
12
- # String, Integer
13
- when String then "<#{key}>#{value}</#{key}>"
14
- when Integer then "<#{key}>#{value}</#{key}>"
15
-
16
12
  # Array
17
13
  when Array
18
14
  # Treat empty arrays as nil values
@@ -22,9 +18,6 @@ def xmlify(key, value)
22
18
  value.each { |x| retval += xmlify("#{key}0", x) }
23
19
  "<#{key}>#{retval}</#{key}>"
24
20
 
25
- # RDT
26
- when ICalPal::RDT then "<#{key}>#{value}</#{key}>"
27
-
28
21
  # Unknown
29
22
  else "<#{key}>#{value}</#{key}>"
30
23
  end
data/lib/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module ICalPal
2
2
  NAME = 'icalPal'.freeze
3
- VERSION = '3.3.0'.freeze
3
+ VERSION = '3.5.0'.freeze
4
4
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: icalPal
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 3.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Rosen
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-24 00:00:00.000000000 Z
10
+ date: 2025-05-13 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: nokogiri-plist
@@ -37,6 +37,26 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: 2.6.0
40
+ - !ruby/object:Gem::Dependency
41
+ name: timezone
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0.99'
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 1.3.0
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0.99'
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: 1.3.0
40
60
  description: |
41
61
  Inspired by icalBuddy and maintains close compatability. Includes
42
62
  many additional features for querying, filtering, and formatting.
@@ -68,6 +88,7 @@ licenses:
68
88
  - GPL-3.0-or-later
69
89
  metadata:
70
90
  bug_tracker_uri: https://github.com/ajrosen/icalPal/issues
91
+ rubygems_mfa_required: 'true'
71
92
  post_install_message: |2+
72
93
 
73
94
  Note: icalPal requires "Full Disk Access" in System Settings to access your calendar.