icalendar2 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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