icalendar2 0.1.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.
Files changed (68) hide show
  1. data/CHANGELOG.md +2 -0
  2. data/README.md +89 -0
  3. data/lib/icalendar2/calendar.rb +85 -0
  4. data/lib/icalendar2/calendar_property/calscale.rb +9 -0
  5. data/lib/icalendar2/calendar_property/method.rb +9 -0
  6. data/lib/icalendar2/calendar_property/prodid.rb +9 -0
  7. data/lib/icalendar2/calendar_property/version.rb +9 -0
  8. data/lib/icalendar2/calendar_property.rb +12 -0
  9. data/lib/icalendar2/component/base.rb +90 -0
  10. data/lib/icalendar2/component/event.rb +32 -0
  11. data/lib/icalendar2/component.rb +8 -0
  12. data/lib/icalendar2/parameter/altrep.rb +8 -0
  13. data/lib/icalendar2/parameter/base.rb +34 -0
  14. data/lib/icalendar2/parameter/cn.rb +8 -0
  15. data/lib/icalendar2/parameter/cutype.rb +8 -0
  16. data/lib/icalendar2/parameter/delegated_from.rb +8 -0
  17. data/lib/icalendar2/parameter/delegated_to.rb +8 -0
  18. data/lib/icalendar2/parameter/dir.rb +8 -0
  19. data/lib/icalendar2/parameter/encoding.rb +8 -0
  20. data/lib/icalendar2/parameter/fmttype.rb +10 -0
  21. data/lib/icalendar2/parameter.rb +4 -0
  22. data/lib/icalendar2/parser.rb +136 -0
  23. data/lib/icalendar2/property/attach.rb +10 -0
  24. data/lib/icalendar2/property/attendee.rb +8 -0
  25. data/lib/icalendar2/property/base.rb +80 -0
  26. data/lib/icalendar2/property/categories.rb +10 -0
  27. data/lib/icalendar2/property/class.rb +9 -0
  28. data/lib/icalendar2/property/comment.rb +8 -0
  29. data/lib/icalendar2/property/contact.rb +8 -0
  30. data/lib/icalendar2/property/description.rb +9 -0
  31. data/lib/icalendar2/property/dtend.rb +9 -0
  32. data/lib/icalendar2/property/dtstamp.rb +9 -0
  33. data/lib/icalendar2/property/dtstart.rb +9 -0
  34. data/lib/icalendar2/property/exdate.rb +10 -0
  35. data/lib/icalendar2/property/geo.rb +9 -0
  36. data/lib/icalendar2/property/last_mod.rb +9 -0
  37. data/lib/icalendar2/property/location.rb +9 -0
  38. data/lib/icalendar2/property/nil.rb +13 -0
  39. data/lib/icalendar2/property/organizer.rb +9 -0
  40. data/lib/icalendar2/property/priority.rb +9 -0
  41. data/lib/icalendar2/property/rdate.rb +8 -0
  42. data/lib/icalendar2/property/related_to.rb +8 -0
  43. data/lib/icalendar2/property/resources.rb +8 -0
  44. data/lib/icalendar2/property/rrule.rb +10 -0
  45. data/lib/icalendar2/property/rstatus.rb +8 -0
  46. data/lib/icalendar2/property/sequence.rb +9 -0
  47. data/lib/icalendar2/property/summary.rb +9 -0
  48. data/lib/icalendar2/property/uid.rb +9 -0
  49. data/lib/icalendar2/property.rb +9 -0
  50. data/lib/icalendar2/tokens.rb +32 -0
  51. data/lib/icalendar2/value/binary_value.rb +8 -0
  52. data/lib/icalendar2/value/boolean_value.rb +6 -0
  53. data/lib/icalendar2/value/cal_address_value.rb +6 -0
  54. data/lib/icalendar2/value/date_time_value.rb +14 -0
  55. data/lib/icalendar2/value/date_value.rb +14 -0
  56. data/lib/icalendar2/value/duration_value.rb +14 -0
  57. data/lib/icalendar2/value/float_value.rb +7 -0
  58. data/lib/icalendar2/value/integer_value.rb +6 -0
  59. data/lib/icalendar2/value/lat_lon_value.rb +6 -0
  60. data/lib/icalendar2/value/period_value.rb +8 -0
  61. data/lib/icalendar2/value/recur_value.rb +39 -0
  62. data/lib/icalendar2/value/text_value.rb +17 -0
  63. data/lib/icalendar2/value/time_value.rb +6 -0
  64. data/lib/icalendar2/value/uri_value.rb +6 -0
  65. data/lib/icalendar2/value.rb +45 -0
  66. data/lib/icalendar2/version.rb +3 -0
  67. data/lib/icalendar2.rb +74 -0
  68. metadata +131 -0
@@ -0,0 +1,80 @@
1
+ module Icalendar2
2
+ module Property
3
+ class Base
4
+ MAX_LINE_LENGTH = 75
5
+ LIST_SEPARATOR = /(?<!\\),/
6
+
7
+ attr_reader :value, :parameters
8
+
9
+ class << self; attr_reader :value_types end
10
+ class << self; attr_reader :value_factories end
11
+
12
+ def self.value(options = {})
13
+ if !options[:types].respond_to?(:map)
14
+ raise ":types option must be enumberable, was #{options[:types]}"
15
+ end
16
+ @value_types = options[:types]
17
+ @value_factories = options[:types].map { |t| Value.get_factory(t) }
18
+ define_method(:list?) do
19
+ options[:list]
20
+ end
21
+ end
22
+
23
+ def self.name(str)
24
+ define_method(:name) { str }
25
+ end
26
+
27
+ def initialize(value, parameters = {})
28
+ @value = if list?
29
+ value_list = value.respond_to?(:map) ? value : value.split(LIST_SEPARATOR)
30
+ value_list.map { |v| value_object(v) }
31
+ else
32
+ value_object(value)
33
+ end
34
+ if @value.nil?
35
+ raise "Invalid value for #{self.class}: '#{value}'. Must be one of these types: #{self.class.value_types}"
36
+ end
37
+ @parameters = parameters || {}
38
+ validate
39
+ end
40
+
41
+ def name
42
+ raise "Must define name attribute in Property sublcass #{self.class}."
43
+ end
44
+
45
+ def valid?
46
+ @valid
47
+ end
48
+
49
+ def to_ical
50
+ parameters_str = @parameters.map { |k, v| "#{k}=#{v}" }.join(";")
51
+ parameters_str = ";#{parameters_str}" if parameters_str != ""
52
+ str = fold("#{name}#{parameters_str}:#{value}")
53
+ str << Tokens::CRLF
54
+ end
55
+
56
+ private
57
+
58
+ def validate
59
+ @valid = if @value.is_a? Array
60
+ @value.all?(&:valid?)
61
+ else
62
+ @value.valid?
63
+ end
64
+ end
65
+
66
+ def value_object(value)
67
+ self.class.value_factories.each do |f|
68
+ obj = f.new(value)
69
+ return obj if obj.valid?
70
+ end
71
+
72
+ nil
73
+ end
74
+
75
+ def fold(str)
76
+ str.scan(/.{1,#{MAX_LINE_LENGTH}}/).join("#{Tokens::CRLF} ")
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,10 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.1.2
4
+ class Categories < Base
5
+ PLURAL = "categories_properties"
6
+ name "CATEGORIES"
7
+ value :types => [:text], :list => true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.1.3
4
+ class Klass < Base
5
+ name "CLASS"
6
+ value :types => [:text]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.1.4
4
+ class Comment < Base
5
+ PLURAL = "comments"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.4.2
4
+ class Contact < Base
5
+ PLURAL = "contacts"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.1.5
4
+ class Description < Base
5
+ name "DESCRIPTION"
6
+ value :types => [:text]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.2.2
4
+ class Dtend < Base
5
+ name "DTEND"
6
+ value :types => [:date, :date_time]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.7.2
4
+ class Dtstamp < Base
5
+ name "DTSTAMP"
6
+ value :types => [:date_time]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.2.4
4
+ class Dtstart < Base
5
+ name "DTSTART"
6
+ value :types => [:date_time, :date]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.5.1
4
+ class Exdate < Base
5
+ PLURAL = "exdates"
6
+ name "EXDATE"
7
+ value :types => [:date_time, :date], :list => true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.1.6
4
+ class Geo < Base
5
+ name "GEO"
6
+ value :types => [:lat_lon]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.7.3
4
+ class LastMod < Base
5
+ name "LAST-MODIFIED"
6
+ value :types => [:date_time]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.1.7
4
+ class Location < Base
5
+ name "LOCATION"
6
+ value :types => [:text]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Icalendar2
2
+ module Property
3
+ class Nil
4
+ def value
5
+ nil
6
+ end
7
+
8
+ def to_ical
9
+ ""
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.4.3
4
+ class Organizer < Base
5
+ name "ORGANIZER"
6
+ value :types => [:cal_address]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.1.9
4
+ class Priority < Base
5
+ name "PRIORITY"
6
+ value :types => [:integer]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.5.2
4
+ class Rdate < Base
5
+ PLURAL = "rdates"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.4.5
4
+ class RelatedTo < Base
5
+ PLURAL = "relateds"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.1.10
4
+ class Resources < Base
5
+ PLURAL = "resources"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.5.3
4
+ class Rrule < Base
5
+ PLURAL = "rrules"
6
+ name "RRULE"
7
+ value :types => [:recur]
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.8.3
4
+ class Rstatus < Base
5
+ PLURAL = "rstatuses"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.7.4
4
+ class Sequence < Base
5
+ name "SEQUENCE"
6
+ value :types => [:integer]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.1.12
4
+ class Summary < Base
5
+ name "SUMMARY"
6
+ value :types => [:text]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ # See http://tools.ietf.org/html/rfc5545#section-3.8.4.7
4
+ class Uid < Base
5
+ name "UID"
6
+ value :types => [:text]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ module Property
3
+ def self.get_factory(property_sym)
4
+ # :foo => "Foo", :bar_baz => "BarBaz", etc.
5
+ property_name = property_sym.to_s.split(/_/).map(&:capitalize).join('')
6
+ const_get(property_name, false)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ module Icalendar2
2
+ module Tokens
3
+ COMPONENT_BEGIN = "BEGIN"
4
+ COMPONENT_END = "END"
5
+ CRLF = "\r\n"
6
+ HTAB = /\t/
7
+ DQUOTE = /"/
8
+ SOLIDUS = /\//
9
+ ALPHA = /[a-zA-Z]/
10
+ DIGIT = /[0-9]/
11
+ CONTROL_CHARS = "\x00-\x08\x0A-\x1F\x7F"
12
+ CONTROL = /[#{CONTROL_CHARS}]/
13
+ QSAFE_CHAR = /[^"#{CONTROL_CHARS}]/
14
+ SAFE_CHAR = /[^"#{CONTROL_CHARS};:,]/
15
+ VALUE_CHAR = /[^#{CONTROL_CHARS}]/
16
+ NON_US_ASCII_CHARS = "\x80-\xFF".force_encoding("UTF-8")
17
+ QUOTED_STRING = /#{DQUOTE}(?:#{SAFE_CHAR})*#{DQUOTE}/
18
+ PARAM_VALUE = "(?:#{SAFE_CHAR})*|#{QUOTED_STRING}"
19
+ IANA_TOKEN = "[-a-zA-Z0-9]+"
20
+ VENDORID = "[a-zA-Z0-9]{3}"
21
+ X_NAME = "X-(?:#{VENDORID}-)?#{IANA_TOKEN}"
22
+
23
+ DATE = /\d{4}(?:0[1-9]|1[012])(?:0[1-9]|[12][0-9]|3[01])/
24
+ TIME = /(?:[01][0-9]|2[0-3])(?:[0-5][0-9])(?:[0-5][0-9]|60)Z?/
25
+ DATE_TIME = /#{DATE}T#{TIME}/
26
+
27
+ # URI components
28
+ SCHEME = "#{ALPHA}(?:#{ALPHA}|#{DIGIT}|[-+.])*"
29
+ HIER_PART = '[^"<>]+'
30
+ URI = "#{SCHEME}:#{HIER_PART}"
31
+ end
32
+ end
@@ -0,0 +1,8 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.1
3
+ class BinaryValue < Value
4
+ B_CHAR = "[a-z0-9+/]"
5
+ B_END = "#{B_CHAR}#{B_CHAR}==|#{B_CHAR}#{B_CHAR}#{B_CHAR}="
6
+ matches /^(?:#{B_CHAR}#{B_CHAR}#{B_CHAR}#{B_CHAR})*(?:#{B_END})?$/i
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.2
3
+ class BooleanValue < Value
4
+ matches /^true$|^false$/i
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.3
3
+ class CalAddressValue < Value
4
+ matches /^#{Tokens::URI}$/
5
+ end
6
+ end
@@ -0,0 +1,14 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.5
3
+ class DateTimeValue < Value
4
+ matches /^#{Tokens::DATE_TIME}$/
5
+
6
+ def initialize(value)
7
+ if value.is_a?(DateTime)
8
+ super(value.strftime('%Y%m%dT%H%M%S'))
9
+ else
10
+ super(value)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.4
3
+ class DateValue < Value
4
+ matches /^#{Tokens::DATE}$/
5
+
6
+ def initialize(value)
7
+ if value.is_a?(Date)
8
+ super(value.strftime('%Y%m%d'))
9
+ else
10
+ super(value)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.6
3
+ class DurationValue < Value
4
+ DUR_DAY = "\\d+D"
5
+ DUR_SECOND = "\\d{1,2}S"
6
+ DUR_MINUTE = "\\d{1,2}M(?:#{DUR_SECOND})?"
7
+ DUR_HOUR = "\\d{1,2}H(?:#{DUR_MINUTE})?"
8
+ DUR_TIME = "T(?:#{DUR_HOUR}|#{DUR_MINUTE}|#{DUR_SECOND})"
9
+ DUR_DATE = "#{DUR_DAY}(?:#{DUR_TIME})?"
10
+ DUR_WEEK = "\\d+W"
11
+ BASE_FORMAT = "P(?:#{DUR_DATE}|#{DUR_TIME}|#{DUR_WEEK})"
12
+ matches /^(?:\+?|-)#{BASE_FORMAT}$/
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.7
3
+ class FloatValue < Value
4
+ BASE_FORMAT = '(?:\+?|-)\d+(?:\.\d+)?'
5
+ matches /^#{BASE_FORMAT}$/
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.8
3
+ class IntegerValue < Value
4
+ matches /^(?:\+?|-)\d+$/
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Icalendar2
2
+ # Made up of two floats separated by a semicolon.
3
+ class LatLonValue < Value
4
+ matches /^#{FloatValue::BASE_FORMAT};#{FloatValue::BASE_FORMAT}$/
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.9
3
+ class PeriodValue < Value
4
+ PERIOD_EXPLICIT = "(?:#{Tokens::DATE_TIME}/#{Tokens::DATE_TIME})"
5
+ PERIOD_START = "(?:#{Tokens::DATE_TIME}/#{DurationValue::BASE_FORMAT})"
6
+ matches /^#{PERIOD_EXPLICIT}|#{PERIOD_START}$/
7
+ end
8
+ end
@@ -0,0 +1,39 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.10
3
+ class RecurValue < Value
4
+ FREQ = "(?:SECONDLY|MINUTELY|HOURLY|DAILY|WEEKLY|MONTHLY|YEARLY)"
5
+ ENDDATE = "(?:#{Tokens::DATE}|#{Tokens::DATE_TIME})"
6
+
7
+ SECONDS = "(?:\d{1,2})"
8
+ BYSECLIST = "(?:#{SECONDS}(?:,#{SECONDS})*)"
9
+
10
+ MINUTES = "(?:\d{1,2})"
11
+ BYMINLIST = "(?:#{MINUTES}(?:,#{MINUTES})*)"
12
+
13
+ HOURS = "(?:\d{1,2})"
14
+ BYHRLIST = "(?:#{HOURS}(?:,#{HOURS})*)"
15
+
16
+ ORDWK = "(?:\d{1,2})"
17
+ WEEKDAY = "(?:SU|MO|TU|WE|TH|FR|SA)"
18
+ WEEKDAYNUM = "(?:[-+]?#{ORDWK}?#{WEEKDAY})"
19
+ BYWDAYLIST = "(?:#{WEEKDAYNUM}(?:,#{WEEKDAYNUM})*)"
20
+
21
+ MONTHDAYNUM = "(?:[-+]?\d{1,2})"
22
+ BYMODAYLIST = "(?:#{MONTHDAYNUM}(?:,#{MONTHDAYNUM})*)"
23
+
24
+ YEARDAYNUM = "(?:[-+]?\d{1,2})"
25
+ BYYRDAYLIST = "(?:#{YEARDAYNUM}(?:,#{YEARDAYNUM})*)"
26
+
27
+ WEEKNUM = "(?:[-+]?\d{1,2})"
28
+ BYWKNOLIST = "(?:#{WEEKNUM}(?:,#{WEEKNUM})*)"
29
+
30
+ MONTHNUM = "(?:\d{1,2})"
31
+ BYMOLIST = "(?:#{MONTHNUM}(?:,#{MONTHNUM})*)"
32
+
33
+ BYSPLIST = "(?:#{YEARDAYNUM}(?:,#{YEARDAYNUM})*)"
34
+
35
+ RECUR_RULE_PART = "FREQ=#{FREQ}|UNTIL=#{ENDDATE}|COUNT=\d+|INTERVAL=\d+|BYSECOND=#{BYSECLIST}|BYMINUTE=#{BYMINLIST}|BYHOUR=#{BYHRLIST}|BYDAY=#{BYWDAYLIST}|BYMONTHDAY=#{BYMODAYLIST}|BYYEARDAY=#{BYYRDAYLIST}|BYWEEKNO=#{BYWKNOLIST}|BYMONTH=#{BYMOLIST}|BYSETPOS=#{BYSPLIST}|WKST=#{WEEKDAY}"
36
+
37
+ matches /^#{RECUR_RULE_PART}(?:;#{RECUR_RULE_PART})*$/
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.11
3
+ # This will escape text passed in, so do not escape it first!
4
+ class TextValue < Value
5
+
6
+ def initialize(value)
7
+ replacements = {
8
+ '\\' => '\\\\',
9
+ ';' => '\;',
10
+ ',' => '\,',
11
+ "\r\n" => "\n",
12
+ "\r" => "\n"
13
+ }
14
+ super(value.respond_to?(:gsub) ? value.gsub(/\\|;|,|\r\n|\r/, replacements) : value)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.12
3
+ class TimeValue < Value
4
+ matches /^#{Tokens::TIME}$/
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.3.13
3
+ class UriValue < Value
4
+ matches /^#{Tokens::URI}$/
5
+ end
6
+ end
@@ -0,0 +1,45 @@
1
+ module Icalendar2
2
+ class Value
3
+
4
+ class << self; attr_reader :format_matcher end
5
+ @format_matcher = nil
6
+
7
+ attr_reader :value
8
+
9
+ def self.matches(matcher)
10
+ @format_matcher = matcher
11
+ end
12
+
13
+ def self.get_factory(value_sym)
14
+ # :foo => "Foo", :bar_baz => "BarBaz", etc.
15
+ value_name = value_sym.to_s.split(/_/).map(&:capitalize).join('')
16
+ Icalendar2.const_get("#{value_name}Value", false)
17
+ end
18
+
19
+ def initialize(value)
20
+ @valid = true
21
+ @value = value
22
+ validate
23
+ end
24
+
25
+ def valid?
26
+ @valid
27
+ end
28
+
29
+ def to_s
30
+ value.to_s
31
+ end
32
+
33
+ private
34
+
35
+ def validate
36
+ unless self.class.format_matcher.nil?
37
+ if value.respond_to?(:to_s) && (val = value.to_s).respond_to?(:match)
38
+ @valid = !!val.match(self.class.format_matcher)
39
+ else
40
+ @valid = false
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module Icalendar2
2
+ VERSION = "0.1.0"
3
+ end