icalendar2 0.1.0 → 0.1.1

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