-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathical-parse.rb
executable file
·126 lines (100 loc) · 2.63 KB
/
ical-parse.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env ruby
require 'awesome_print'
class Element
BEGIN_REGEXP = /^BEGIN:([A-Z]+)\s*$/
ATTR_REGEXP = /^(.+?):(.+)$/
DESCRIPTION_REGEXP = /^DESCRIPTION:(.*)$/
def initialize(io, begin_line, output_io = nil)
raise "Expected a BEGIN line!" unless begin_line =~ BEGIN_REGEXP
@name = $1
@io = io
@begin_line = begin_line
@output_io = output_io
end
def parse
@body = {}
@io.each do |line|
dump(line)
next if description?(line)
line.rstrip!
case line
when /^END:#{@name}$/
break
when BEGIN_REGEXP
inner = Element.new(@io, line, @output_io).parse
el_key = inner.keys[0]
@body[el_key] ||= []
@body[el_key] << inner[el_key]
when ATTR_REGEXP
if @body[$1]
@body[$1] = [@body[$1]] unless @body[$1].is_a?(Array)
@body[$1] << $2
else
@body[$1] = $2
end
else
raise "Unexpected line: '#{line}'!"
end
end
{ @name => @body }
end
private
def description?(line)
return false unless @parsing_description || description_match = (line =~ DESCRIPTION_REGEXP)
if @parsing_description
if line =~ /^ /
@parsing_description << line
else
@parsing_description = @parsing_description[0] if @parsing_description.size == 1
@body["DESCRIPTION"] = @parsing_description
@parsing_description = false
end
else
@parsing_description = [$1]
end
end
def dump(line)
return unless @output_io
@output_io.puts line
end
end
class IcalParser
def self.parse(in_filename, out_filename = nil)
unless in_filename && File.exist?(in_filename)
puts "File #{in_filename} doesn't exist!"
exit 1
end
if out_filename
out = File.open(out_filename, "w")
end
File.open(in_filename, "r") do |f|
first_line = f.gets
out.puts first_line if out
root = Element.new(f, first_line, out)
@parsed = root.parse
end
if out_filename
out.close
end
clean_exdates
clean_rrules
ap @parsed
end
private
def self.clean_exdates
@parsed["VCALENDAR"]["VEVENT"].each do |vevent|
next unless vevent["EXDATE;VALUE=DATE"]
dates = vevent["EXDATE;VALUE=DATE"]
dates.sort!
vevent["EXDATE;VALUE=DATE"] = dates.last
end
end
def self.clean_rrules
@parsed["VCALENDAR"]["VEVENT"].each do |vevent|
next unless vevent["DTSTART;VALUE=DATE"] && vevent["DTEND;VALUE=DATE"]
vevent["RRULE"].sub!(/;UNTIL=\d{8}/, "")
vevent["RRULE"].sub!(/;BYMONTH=\d{1,2}/, "")
end
end
end
IcalParser.parse ARGV[0], ARGV[1]