kali 0.0.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.
@@ -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