icalendar2 0.1.0 → 0.1.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.
data/CHANGELOG.md CHANGED
@@ -1,2 +1,5 @@
1
- 0.1.0
1
+ 0.1.1 2012-12-13
2
+ * Pass tests under Ruby 1.8.7 [#2]
3
+
4
+ 0.1.0 2012-12-12
2
5
  * Initial commit
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # icalendar2 - generate, consume and validate iCalendar feeds
2
2
 
3
+ [![Build Status](https://travis-ci.org/ericcf/icalendar2.png?branch=master)](https://travis-ci.org/ericcf/icalendar2)
4
+
3
5
  ## Warning
4
6
 
5
7
  This is NOT production ready yet. It has not been extensively tested, and you
@@ -8,10 +8,10 @@ module Icalendar2
8
8
  Event::VALUE => []
9
9
  }
10
10
  @properties = {
11
- :calscale => Property::Nil.new,
12
- :method => Property::Nil.new,
13
- :prodid => Property::Nil.new,
14
- :version => Property::Nil.new
11
+ "calscale" => Property::Nil.new,
12
+ "method" => Property::Nil.new,
13
+ "prodid" => Property::Nil.new,
14
+ "version" => Property::Nil.new
15
15
  }
16
16
  end
17
17
 
@@ -32,7 +32,7 @@ module Icalendar2
32
32
  end
33
33
 
34
34
  def set_property(property_name, value, parameters = {})
35
- property = property_name.downcase.to_sym
35
+ property = property_name.to_s.downcase
36
36
  if value.nil?
37
37
  @properties[property].value.to_s
38
38
  elsif (factory = CalendarProperty.get_factory(property_name))
@@ -64,7 +64,9 @@ module Icalendar2
64
64
  str = "#{Tokens::COMPONENT_BEGIN}:#{VALUE}#{Tokens::CRLF}"
65
65
  str << body_to_ical
66
66
  str << "#{Tokens::COMPONENT_END}:#{VALUE}#{Tokens::CRLF}"
67
- str.encode("UTF-8")
67
+ str = str.encode("UTF-8") if str.respond_to?(:encode)
68
+
69
+ str
68
70
  end
69
71
 
70
72
  def add_component(component)
@@ -78,7 +80,8 @@ module Icalendar2
78
80
  private
79
81
 
80
82
  def body_to_ical
81
- str = @properties.values.map(&:to_ical).join
83
+ sorted_properties = @properties.zip.map(&:first).sort
84
+ str = sorted_properties.map { |p| p[1] && p[1].to_ical }.join
82
85
  str << events.map(&:to_ical).join
83
86
  end
84
87
  end
@@ -3,7 +3,8 @@ module Icalendar2
3
3
  def self.get_factory(calendar_property_name)
4
4
  # "VERSION" => CalendarProperty::Version, etc.
5
5
  begin
6
- const_get(calendar_property_name.capitalize, false)
6
+ property_class_name = calendar_property_name.to_s.capitalize
7
+ const_get(property_class_name) if const_defined?(property_class_name)
7
8
  rescue NameError
8
9
  nil
9
10
  end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.6.6
3
+ class Alarm < Component::Base
4
+ VALUE = "VALARM"
5
+
6
+ requires :exactly_one => [:action, :trigger]
7
+ accepts :exactly_one => [:description, :duration, :repeat, :attach]
8
+ end
9
+ end
@@ -31,7 +31,7 @@ module Icalendar2
31
31
  def valid?
32
32
  present_property_names = @properties.keys
33
33
  @properties.values.flatten.all?(&:valid?) &&
34
- self.class.required_property_names.all? { |p| present_property_names.include?(p) }
34
+ self.class.required_property_names.all? { |p| present_property_names.include?(p.to_s) }
35
35
  end
36
36
 
37
37
  def set_property(property_name, value, parameters = {})
@@ -61,9 +61,9 @@ module Icalendar2
61
61
  define_method(property_sym) do |*args|
62
62
  value, parameters = *args
63
63
  if value.nil?
64
- @properties[property_sym]
64
+ @properties[property_sym.to_s]
65
65
  else
66
- @properties[property_sym] = Property.get_factory(property_sym).new(value, parameters)
66
+ @properties[property_sym.to_s] = Property.get_factory(property_sym).new(value, parameters)
67
67
  end
68
68
  end
69
69
  alias_method "#{property_sym}=", property_sym
@@ -72,18 +72,19 @@ module Icalendar2
72
72
  def self.define_multiple_accessor(property_sym)
73
73
  property_factory = Property.get_factory(property_sym)
74
74
  define_method(property_factory::PLURAL) do
75
- @properties[property_sym]
75
+ @properties[property_sym.to_s]
76
76
  end
77
77
  define_method(property_sym) do |*args|
78
78
  value, parameters = *args
79
- @properties[property_sym] ||= []
80
- @properties[property_sym] << property_factory.new(value, parameters)
79
+ @properties[property_sym.to_s] ||= []
80
+ @properties[property_sym.to_s] << property_factory.new(value, parameters)
81
81
  end
82
82
  alias_method "#{property_sym}=", property_sym
83
83
  end
84
84
 
85
85
  def properties_to_ical
86
- @properties.values.flatten.map(&:to_ical).join
86
+ sorted_properties = @properties.zip.map(&:first).sort
87
+ sorted_properties.map { |p| p[1] && p[1].to_ical }.join
87
88
  end
88
89
  end
89
90
  end
@@ -0,0 +1,16 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.6.4
3
+ class Freebusy < Component::Base
4
+ VALUE = "VFREEBUSY"
5
+
6
+ requires :exactly_one => [:dtstamp, :uid]
7
+ accepts :exactly_one => [:contact, :dtstart, :dtend, :organizer, :url],
8
+ :one_or_more => [:attendee, :comment, :freebusy, :rstatus]
9
+
10
+ def initialize
11
+ super
12
+ self.uid = new_uid
13
+ self.dtstamp = new_timestamp
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.6.3
3
+ class Journal < Component::Base
4
+ VALUE = "VJOURNAL"
5
+
6
+ requires :exactly_one => [:dtstamp, :uid]
7
+ accepts :exactly_one => [:klass, :created, :dtstart, :last_mod, :organizer,
8
+ :recurid, :seq, :status, :summary, :url],
9
+ :one_or_more => [:rrule, :attach, :attendee, :categories, :comment,
10
+ :contact, :description, :exdate, :related_to, :rdate, :rstatus]
11
+
12
+ def initialize
13
+ super
14
+ self.uid = new_uid
15
+ self.dtstamp = new_timestamp
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.6.5
3
+ class Timezone < Component::Base
4
+ VALUE = "VTIMEZONE"
5
+
6
+ requires :exactly_one => [:tzid]
7
+ accepts :exactly_one => [:last_mod, :tzurl]
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ module Icalendar2
2
+ # See http://tools.ietf.org/html/rfc5545#section-3.6.2
3
+ class Todo < Component::Base
4
+ VALUE = "VTODO"
5
+
6
+ requires :exactly_one => [:dtstamp, :uid]
7
+ accepts :exactly_one => [:klass, :completed, :created, :description,
8
+ :dtstart, :geo, :last_mod, :location, :organizer, :percent, :priority,
9
+ :recurid, :seq, :status, :summary, :url, :due, :duration],
10
+ :one_or_more => [:rrule, :attach, :attendee, :categories, :comment,
11
+ :contact, :exdate, :rstatus, :related_to, :resources, :rdate]
12
+
13
+ def initialize
14
+ super
15
+ self.uid = new_uid
16
+ self.dtstamp = new_timestamp
17
+ end
18
+ end
19
+ end
@@ -2,7 +2,8 @@ module Icalendar2
2
2
  module Component
3
3
  def self.get_factory(component_name)
4
4
  # "VFOO" => "Foo", etc.
5
- Icalendar2.const_get(component_name.gsub(/^V/, "").capitalize, false)
5
+ component_class_name = component_name.gsub(/^V/, "").capitalize
6
+ Icalendar2.const_get(component_class_name) if Icalendar2.const_defined?(component_class_name)
6
7
  end
7
8
  end
8
9
  end
@@ -2,7 +2,6 @@ module Icalendar2
2
2
  module Property
3
3
  class Base
4
4
  MAX_LINE_LENGTH = 75
5
- LIST_SEPARATOR = /(?<!\\),/
6
5
 
7
6
  attr_reader :value, :parameters
8
7
 
@@ -26,7 +25,7 @@ module Icalendar2
26
25
 
27
26
  def initialize(value, parameters = {})
28
27
  @value = if list?
29
- value_list = value.respond_to?(:map) ? value : value.split(LIST_SEPARATOR)
28
+ value_list = value.respond_to?(:gsub) ? split_list(value) : value
30
29
  value_list.map { |v| value_object(v) }
31
30
  else
32
31
  value_object(value)
@@ -55,9 +54,11 @@ module Icalendar2
55
54
 
56
55
  private
57
56
 
57
+ LIST_SEPARATOR = /([^\\]),/
58
+
58
59
  def validate
59
60
  @valid = if @value.is_a? Array
60
- @value.all?(&:valid?)
61
+ @value.compact.all?(&:valid?)
61
62
  else
62
63
  @value.valid?
63
64
  end
@@ -75,6 +76,11 @@ module Icalendar2
75
76
  def fold(str)
76
77
  str.scan(/.{1,#{MAX_LINE_LENGTH}}/).join("#{Tokens::CRLF} ")
77
78
  end
79
+
80
+ def split_list(str)
81
+ # Ruby 1.8.7 doesn't support negative lookbehind, so using this hack...
82
+ str.gsub(LIST_SEPARATOR, "\\1x,").split(/x,/)
83
+ end
78
84
  end
79
85
  end
80
86
  end
@@ -3,7 +3,7 @@ module Icalendar2
3
3
  def self.get_factory(property_sym)
4
4
  # :foo => "Foo", :bar_baz => "BarBaz", etc.
5
5
  property_name = property_sym.to_s.split(/_/).map(&:capitalize).join('')
6
- const_get(property_name, false)
6
+ const_get(property_name) if const_defined?(property_name)
7
7
  end
8
8
  end
9
9
  end
@@ -13,7 +13,7 @@ module Icalendar2
13
13
  QSAFE_CHAR = /[^"#{CONTROL_CHARS}]/
14
14
  SAFE_CHAR = /[^"#{CONTROL_CHARS};:,]/
15
15
  VALUE_CHAR = /[^#{CONTROL_CHARS}]/
16
- NON_US_ASCII_CHARS = "\x80-\xFF".force_encoding("UTF-8")
16
+ NON_US_ASCII_CHARS = "\x80-\xFF"
17
17
  QUOTED_STRING = /#{DQUOTE}(?:#{SAFE_CHAR})*#{DQUOTE}/
18
18
  PARAM_VALUE = "(?:#{SAFE_CHAR})*|#{QUOTED_STRING}"
19
19
  IANA_TOKEN = "[-a-zA-Z0-9]+"
@@ -4,14 +4,11 @@ module Icalendar2
4
4
  class TextValue < Value
5
5
 
6
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)
7
+ if value.respond_to?(:gsub)
8
+ super(value.gsub(/\\/, "\\\\\\").gsub(';', '\;').gsub(',', '\,').gsub("\r\n", "\n").gsub("\r", "\n"))
9
+ else
10
+ super(value)
11
+ end
15
12
  end
16
13
  end
17
14
  end
@@ -13,7 +13,8 @@ module Icalendar2
13
13
  def self.get_factory(value_sym)
14
14
  # :foo => "Foo", :bar_baz => "BarBaz", etc.
15
15
  value_name = value_sym.to_s.split(/_/).map(&:capitalize).join('')
16
- Icalendar2.const_get("#{value_name}Value", false)
16
+ value_class_name = "#{value_name}Value"
17
+ Icalendar2.const_get(value_class_name) if Icalendar2.const_defined?(value_class_name)
17
18
  end
18
19
 
19
20
  def initialize(value)
@@ -1,3 +1,3 @@
1
1
  module Icalendar2
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/lib/icalendar2.rb CHANGED
@@ -8,6 +8,11 @@ module Icalendar2
8
8
 
9
9
  autoload :Component, "icalendar2/component"
10
10
  autoload :Event, "icalendar2/component/event"
11
+ autoload :Todo, "icalendar2/component/todo"
12
+ autoload :Journal, "icalendar2/component/journal"
13
+ autoload :Freebusy, "icalendar2/component/freebusy"
14
+ autoload :Timezone, "icalendar2/component/timezone"
15
+ autoload :Alarm, "icalendar2/component/alarm"
11
16
  module Component
12
17
  autoload :Base, "icalendar2/component/base"
13
18
  end
metadata CHANGED
@@ -1,50 +1,60 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: icalendar2
3
- version: !ruby/object:Gem::Version
4
- version: 0.1.0
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Eric Carty-Fickes
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2012-12-12 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2012-12-13 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
15
21
  name: rspec
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ~>
20
- - !ruby/object:Gem::Version
21
- version: '2'
22
- type: :development
23
22
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
23
+ requirement: &id001 !ruby/object:Gem::Requirement
25
24
  none: false
26
- requirements:
25
+ requirements:
27
26
  - - ~>
28
- - !ruby/object:Gem::Version
29
- version: '2'
30
- description: Borrows fromt the API used by the icalendar Ruby gem. Outputs iCalendar
31
- (RFC 5545) formatted text.
32
- email:
27
+ - !ruby/object:Gem::Version
28
+ hash: 7
29
+ segments:
30
+ - 2
31
+ version: "2"
32
+ type: :development
33
+ version_requirements: *id001
34
+ description: Borrows fromt the API used by the icalendar Ruby gem. Outputs iCalendar (RFC 5545) formatted text.
35
+ email:
33
36
  - ericcf@northwestern.edu
34
37
  executables: []
38
+
35
39
  extensions: []
36
- extra_rdoc_files:
40
+
41
+ extra_rdoc_files:
37
42
  - CHANGELOG.md
38
43
  - README.md
39
- files:
44
+ files:
40
45
  - lib/icalendar2/calendar.rb
41
46
  - lib/icalendar2/calendar_property/calscale.rb
42
47
  - lib/icalendar2/calendar_property/method.rb
43
48
  - lib/icalendar2/calendar_property/prodid.rb
44
49
  - lib/icalendar2/calendar_property/version.rb
45
50
  - lib/icalendar2/calendar_property.rb
51
+ - lib/icalendar2/component/alarm.rb
46
52
  - lib/icalendar2/component/base.rb
47
53
  - lib/icalendar2/component/event.rb
54
+ - lib/icalendar2/component/freebusy.rb
55
+ - lib/icalendar2/component/journal.rb
56
+ - lib/icalendar2/component/timezone.rb
57
+ - lib/icalendar2/component/todo.rb
48
58
  - lib/icalendar2/component.rb
49
59
  - lib/icalendar2/parameter/altrep.rb
50
60
  - lib/icalendar2/parameter/base.rb
@@ -106,26 +116,36 @@ files:
106
116
  - README.md
107
117
  homepage: https://github.com/ericcf/icalendar2
108
118
  licenses: []
119
+
109
120
  post_install_message:
110
121
  rdoc_options: []
111
- require_paths:
122
+
123
+ require_paths:
112
124
  - lib
113
- required_ruby_version: !ruby/object:Gem::Requirement
125
+ required_ruby_version: !ruby/object:Gem::Requirement
114
126
  none: false
115
- requirements:
116
- - - ! '>='
117
- - !ruby/object:Gem::Version
118
- version: '0'
119
- required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ hash: 3
131
+ segments:
132
+ - 0
133
+ version: "0"
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
135
  none: false
121
- requirements:
122
- - - ! '>='
123
- - !ruby/object:Gem::Version
124
- version: '0'
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ hash: 3
140
+ segments:
141
+ - 0
142
+ version: "0"
125
143
  requirements: []
144
+
126
145
  rubyforge_project:
127
146
  rubygems_version: 1.8.24
128
147
  signing_key:
129
148
  specification_version: 3
130
149
  summary: iCalendar (RFC 5545) Ruby library
131
150
  test_files: []
151
+