kali 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ # Kali: iCalendar for the rest of us
2
+
3
+ Kali attempts to provide a simple and extensible implementation of [RFC
4
+ 5545][rfc5545] and friends, which describe the iCalendar format, used for
5
+ representing and exchanging calendaring and scheduling information.
6
+
7
+ [Kālī][wikipedia] is also the Hindu Goddess of Time.
8
+
9
+ ![Kali: Goddess of Time and Change, by Raja Ravi Varma](
10
+ http://upload.wikimedia.org/wikipedia/commons/8/89/Kali_by_Raja_Ravi_Varma.jpg
11
+ )
12
+
13
+ ## Generating Calendars
14
+
15
+ The simplest example possible:
16
+
17
+ ``` ruby
18
+ require "uri"
19
+ require "kali"
20
+
21
+ calendar = Kali::Calendar.new do |cal|
22
+ cal.event do |event|
23
+ event.summary = "Lunch" # Or: event.summary = Kali::Property::Summary.new("Lunch")
24
+ event.description = "Let's get some food"
25
+ event.dtstart = DateTime.civil(2013, 7, 31, 12, 30)
26
+ event.dtend = DateTime.civil(2013, 7, 31, 14, 30)
27
+
28
+ event.attendees.add URI("mailto:hi@nicolassanguinetti.info") do |attendee|
29
+ attendee.partstat = "ACCEPTED"
30
+ attendee.cn = "Nicolás Sanguinetti"
31
+ attendee["X-GUEST-COUNT"] = 2
32
+ end
33
+
34
+ event.attendees.add URI("mailto:someone@example.com") # Simplified attendee
35
+ end
36
+ end
37
+
38
+ File.open("cal.ics", "w") { |f| f.puts(calendar.to_ics) }
39
+ ```
40
+
41
+ [rfc5545]: http://tools.ietf.org/html/rfc5545
42
+ [wikipedia]: http://en.wikipedia.org/wiki/Kali
@@ -0,0 +1,48 @@
1
+ require "kali"
2
+ require "uri"
3
+
4
+ cal = Kali::Calendar.new do |calendar|
5
+ calendar.events.add do |event|
6
+ event.uid = 1
7
+ event.summary = "Conference Talk"
8
+
9
+ event.description = "A description of the talk"
10
+ event.description.language = "en" # setting parameters on properties.
11
+
12
+ event.location = "The Venue"
13
+ event.geo = [-54.458594, -34.123310]
14
+ event.categories = ["CATEGORY A", "CATEGORY B"]
15
+
16
+ event.dtstart = DateTime.civil(2013, 7, 31, 15, 00, 00, "-07:00")
17
+ event.dtstart.tzid = "America/Los_Angeles"
18
+ event.dtend = DateTime.civil(2013, 7, 31, 16, 00, 00, "-07:00")
19
+ event.dtend.tzid = "America/Los_Angeles"
20
+
21
+ event.comments.add "I'm sure the talk will be a disaster --The Speaker"
22
+ event.comments.add "Estoy convencido de que va a ser buena" do |comment|
23
+ comment.language = "es"
24
+ end
25
+
26
+ event.attendees.add URI.parse("mailto:john@example.org") do |attendee|
27
+ attendee.partstat = "ACCEPTED"
28
+ attendee.role = "CHAIR"
29
+ end
30
+
31
+ event.attendees.add URI.parse("mailto:jane@example.org") do |attendee|
32
+ # the property parameters can be specified as if the property was a Hash.
33
+ attendee["PARTSTAT"] = "DECLINED"
34
+ end
35
+ end
36
+
37
+ calendar.events.add do |event|
38
+ event.uid = 2
39
+ event.summary = "Another Thing"
40
+ event.location = "The Venue"
41
+
42
+ event.dtstart = DateTime.new(2013, 7, 31, 18, 00, 00, "+02:00")
43
+ event.dtstart["TZID"] = "Europe/Berlin"
44
+ event.duration = { minute: 45 }
45
+ end
46
+ end
47
+
48
+ puts cal.to_ics
@@ -0,0 +1,16 @@
1
+ require "kali/version"
2
+ require "kali/type"
3
+ require "kali/utils"
4
+ require "kali/key_value_pair"
5
+ require "kali/typed_list"
6
+ require "kali/property"
7
+ require "kali/parameter"
8
+ require "kali/component"
9
+ require "kali/parameters"
10
+ require "kali/properties"
11
+
12
+ require "kali/component/calendar"
13
+ require "kali/component/event"
14
+
15
+ module Kali
16
+ end
@@ -0,0 +1,128 @@
1
+ module Kali
2
+ class Component
3
+ extend Utils::Named
4
+
5
+ # Public: Add a property to this component. This property will appear 0 or 1
6
+ # times in this component. If you want to add a property that can appear
7
+ # multiple times in the component, look at `Component.property_list`.
8
+ #
9
+ # Example
10
+ #
11
+ # class Event < Kali::Component
12
+ # property Kali::Property::Summary
13
+ # property Kali::Property::Description, :desc
14
+ # end
15
+ #
16
+ # Event.new do |event|
17
+ # event.summary = "Summary"
18
+ # event.desc = "Description"
19
+ # end
20
+ #
21
+ # type - The class that defines the property. Must be a Kali::Property
22
+ # subclass.
23
+ # method - The name of the method under which to mount this property.
24
+ #
25
+ # Returns nothing.
26
+ def self.property(type, method = type.method_name)
27
+ define_method method do
28
+ properties[type.name] ||= type.new
29
+ end
30
+
31
+ define_method "#{method}=" do |value|
32
+ property = type === value ? value : type.new(value)
33
+ properties[type.name] = property
34
+ end
35
+ end
36
+
37
+ # Public: Add a family of properties to this component. This adds a property
38
+ # that can appear multiple times in this component. If you need a property
39
+ # that appears at most once in the component, look at `Component.property`.
40
+ #
41
+ # Example
42
+ #
43
+ # class Event < Kali::Component
44
+ # property_list Kali::Property::Attendee, :attendees
45
+ # end
46
+ #
47
+ # Event.new do |event|
48
+ # event.attendees.add do |attendee|
49
+ # ...
50
+ # end
51
+ # end
52
+ #
53
+ # type - The class that defines the property. Must be a Kali::Property
54
+ # subclass.
55
+ # method - The name of the method under which to mount this property.
56
+ #
57
+ # Returns nothing.
58
+ def self.property_list(type, method = type.method_name)
59
+ define_method method do
60
+ properties[type.name] ||= TypedList.new(type)
61
+ end
62
+ end
63
+
64
+ # Public: Add a family of components to this component. This exposes a list
65
+ # to which you can add sub-components.
66
+ #
67
+ # Example
68
+ #
69
+ # class Calendar < Kali::Component
70
+ # component Kali::Event, :events
71
+ # end
72
+ #
73
+ # Calendar.new do |cal|
74
+ # cal.events.add do |event|
75
+ # ...
76
+ # end
77
+ # end
78
+ #
79
+ # type - The class that defines the component. Must be a Kali::Component
80
+ # subclass.
81
+ # method - The name of the method under which to mount this property.
82
+ #
83
+ # Returns nothing.
84
+ def self.component(type, method = type.method_name)
85
+ define_method method do
86
+ components[type.name] ||= TypedList.new(type)
87
+ end
88
+ end
89
+
90
+ # Public: Initialize the component.
91
+ #
92
+ # Yields itself if a block is passed.
93
+ def initialize
94
+ yield self if block_given?
95
+ end
96
+
97
+ # Public: Generate an iCalendar representation of the component.
98
+ #
99
+ # Returns a String.
100
+ def to_ics
101
+ properties = self.properties.map { |_, value| value.to_ics }
102
+ components = self.components.map { |_, value| value.to_ics }
103
+
104
+ lines = [
105
+ "BEGIN:#{self.class.name}",
106
+ *properties.compact,
107
+ *components.compact,
108
+ "END:#{self.class.name}"
109
+ ]
110
+
111
+ lines.reject { |s| s.empty? }.join("\n")
112
+ end
113
+
114
+ # Internal: List of properties stored in this component.
115
+ #
116
+ # Returns a Hash.
117
+ def properties
118
+ @properties ||= {}
119
+ end
120
+
121
+ # Internal: List of sub-components that form this component.
122
+ #
123
+ # Returns a Hash.
124
+ def components
125
+ @components ||= {}
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,23 @@
1
+ require "kali/component"
2
+ require "kali/properties"
3
+ require "kali/component/event"
4
+
5
+ module Kali
6
+ class Calendar < Component
7
+ name "VCALENDAR"
8
+
9
+ component Event, :events
10
+
11
+ property Property::ProductIdentifier
12
+ property Property::Version
13
+ property Property::CalendarScale
14
+ property Property::Method
15
+
16
+ def initialize
17
+ self.prodid = Property::ProductIdentifier.new
18
+ self.version = Property::Version.new
19
+ self.calscale = Property::CalendarScale.new
20
+ super
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ require "kali/component"
2
+ require "kali/properties"
3
+
4
+ module Kali
5
+ class Event < Component
6
+ name "VEVENT"
7
+
8
+ property Property::UniqueIdentifier
9
+ property Property::SequenceNumber
10
+ property Property::Summary
11
+ property Property::Description
12
+ property Property::GeographicPosition
13
+ property Property::Location
14
+ property Property::Priority
15
+ property Property::Resources
16
+ property Property::Categories
17
+ property Property::EventStatus
18
+ property Property::StartDateTime
19
+ property Property::EndDateTime
20
+ property Property::Duration
21
+ property Property::TimeTransparency
22
+ property Property::Organizer
23
+ property Property::Contact
24
+
25
+ property_list Property::Comment, :comments
26
+ property_list Property::Attendee, :attendees
27
+
28
+ def initialize
29
+ self.sequence = Property::SequenceNumber.new
30
+ super
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,62 @@
1
+ module Kali
2
+ class KeyValuePair
3
+ extend Utils::Named
4
+
5
+ # Internal: Given a value for this KV-pair, if it's already of the pair's
6
+ # type, return it as is, or otherwise instantiate a new pair with this as a
7
+ # value.
8
+ #
9
+ # Returns an instance of this KV-pair's type.
10
+ def self.wrap(value)
11
+ self === value ? value : new(value)
12
+ end
13
+
14
+ # Public: Get/Set the Type of the KV-pair implemented by this class.
15
+ def self.type(type = nil)
16
+ @type = type if type
17
+ @type
18
+ end
19
+
20
+ # Public: Get/Set a default value for this KV-pair.
21
+ def self.default(default = nil)
22
+ @default = default if default
23
+ @default
24
+ end
25
+
26
+ # Public: Get/Set the value of this specific instance of the KV-pair.
27
+ attr_accessor :value
28
+
29
+ # Internal: Initialize the KV-pair.
30
+ #
31
+ # value - Any value that can be set for this KV-pair.
32
+ def initialize(value = self.class.default)
33
+ @value = value
34
+ end
35
+
36
+ # Public: Generate an iCalendar representation of this KV-pair.
37
+ #
38
+ # Returns a String.
39
+ def to_ics
40
+ encoded_value = self.class.type.encode(value)
41
+ "#{name}#{separator}#{encoded_value}"
42
+ end
43
+
44
+ # Public: Get the String representation of this KV-pair.
45
+ def to_s
46
+ value.to_s
47
+ end
48
+
49
+ # Internal: Get the name of the KV-pair.
50
+ def name
51
+ @name ||= self.class.name
52
+ end
53
+
54
+ # Internal: Separator of the key and value in iCalendar representations of
55
+ # this KV-pair.
56
+ #
57
+ # Returns a String.
58
+ def separator
59
+ ":"
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,14 @@
1
+ module Kali
2
+ # Public: Parameters are meta-information about a certain property.
3
+ class Parameter < KeyValuePair
4
+ # Public: See KeyValuePair#to_ics
5
+ def to_ics
6
+ ";#{super}"
7
+ end
8
+
9
+ # Internal: See KeyValuePair#separator
10
+ def separator
11
+ "="
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,146 @@
1
+ module Kali
2
+ # Public: Meta-property that represents any user-defined property not
3
+ # currently implemented in the system.
4
+ class Parameter::Default < Parameter
5
+ type Type::Text.new
6
+
7
+ def initialize(name, value)
8
+ @name = name
9
+ super(value)
10
+ end
11
+ end
12
+
13
+ # URI pointing to an alternate representation of the value of the property to
14
+ # which this parameter applies to.
15
+ #
16
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.1
17
+ class Parameter::AlternateRepresentation < Parameter
18
+ name "ALTREP"
19
+ type Type::Quoted.new(Type::URI.new)
20
+ end
21
+
22
+ # Common name of a calendar user. Specified in properties with the type
23
+ # CalAddress.
24
+ #
25
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.2
26
+ class Parameter::CommonName < Parameter
27
+ name "CN"
28
+ type Type::Quoted.new(Type::Text.new)
29
+ end
30
+
31
+ # Identifies the type of user to which this property refers to.
32
+ #
33
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.3
34
+ class Parameter::CalendarUserType < Parameter
35
+ name "CUTYPE"
36
+ type Type::Text.new(Enum["INDIVIDUAL", "GROUP", "RESOURCE", "ROOM",
37
+ "UNKNOWN"])
38
+ default "INDIVIDUAL"
39
+ end
40
+
41
+ # List of users that have delegated their participation to the calendar user
42
+ # specified by the property to which this parameter applies.
43
+ #
44
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.4
45
+ class Parameter::Delegators < Parameter
46
+ name "DELEGATED-FROM"
47
+ type Type::List.new(Type::Quoted.new(Type::CalAddress.new))
48
+ end
49
+
50
+ # List of users to which the calendar user has delegated his/her participation
51
+ # to.
52
+ #
53
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.5
54
+ class Parameter::Delegatees < Parameter
55
+ name "DELEGATED-TO"
56
+ type Type::List.new(Type::Quoted.new(Type::CalAddress.new))
57
+ end
58
+
59
+ # URI pointing to a directory entry associated with the calendar user to which
60
+ # this parameter applies.
61
+ #
62
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.6
63
+ class Parameter::DirectoryEntry < Parameter
64
+ name "DIR"
65
+ type Type::Quoted.new(Type::URI.new)
66
+ end
67
+
68
+ # Alternate encoding for the value of this property.
69
+ #
70
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.7
71
+ class Parameter::Encoding < Parameter
72
+ name "ENCODING"
73
+ type Type::Text.new(Enum["8BIT", "BASE64"])
74
+ default "8BIT"
75
+ end
76
+
77
+ # Specifies the content type of the referenced object.
78
+ #
79
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.8
80
+ class Parameter::ContentType < Parameter
81
+ name "FMTTYPE"
82
+ type Type::Text.new(/[a-z0-9\!\#\$\&\.\+\-\^\_]{1,127}\/[a-z0-9\!\#\$\&\.\+\-\^\_]{1,127}/i)
83
+ end
84
+
85
+ # Specifies the language of the associated property (using an identifier as
86
+ # conceived by [RFC 5646](http://tools.ietf.org/html/rfc5646)).
87
+ #
88
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.10
89
+ class Parameter::Language < Parameter
90
+ name "LANGUAGE"
91
+ type Type::Text.new
92
+ end
93
+
94
+ # Mailing lists/groups of which the calendar user is a member of.
95
+ #
96
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.11
97
+ class Parameter::GroupMemberships < Parameter
98
+ name "MEMBER"
99
+ type Type::List.new(Type::Quoted.new(Type::CalAddress.new))
100
+ end
101
+
102
+ # Current status of participation in an event of the calendar user.
103
+ #
104
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.12
105
+ class Parameter::EventParticipationStatus < Parameter
106
+ name "PARTSTAT"
107
+ type Type::Text.new(Enum["NEEDS-ACTION", "ACCEPTED", "DECLINED",
108
+ "TENTATIVE", "DELEGATED"])
109
+ end
110
+
111
+ # Role within the event of the calendar user described by this property.
112
+ #
113
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.16
114
+ class Parameter::ParticipationRole < Parameter
115
+ name "ROLE"
116
+ type Type::Text.new(Enum["CHAIR", "REQ-PARTICIPANT", "OPT-PARTICIPANT",
117
+ "NON-PARTICIPANT"])
118
+ default "REQ-PARTICIPANT"
119
+ end
120
+
121
+ # Specified whether a reply is expected from the calendar user.
122
+ #
123
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.17
124
+ class Parameter::RSVPExpectation < Parameter
125
+ name "RSVP"
126
+ type Type::Boolean.new
127
+ default false
128
+ end
129
+
130
+ # Specify that the described calendar user is acting on behalf of the calendar
131
+ # user addressed by this parameter.
132
+ #
133
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.18
134
+ class Parameter::SentBy < Parameter
135
+ name "SENT-BY"
136
+ type Type::Quoted.new(Type::CalAddress.new)
137
+ end
138
+
139
+ # Specify the timezone in which this Time or DateTime is occurring.
140
+ #
141
+ # See http://tools.ietf.org/html/rfc5545#section-3.2.19
142
+ class Parameter::TimeZoneIdentifier < Parameter
143
+ name "TZID"
144
+ type Type::Text.new
145
+ end
146
+ end