ical_builder 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +7 -0
- data/Rakefile +48 -0
- data/VERSION.yml +4 -0
- data/ical_builder.gemspec +52 -0
- data/init.rb +2 -0
- data/lib/ical_builder.rb +94 -0
- data/lib/ical_template.rb +17 -0
- data/rails/init.rb +1 -0
- data/test/ical_builder_test.rb +140 -0
- data/test/test_helper.rb +10 -0
- metadata +92 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Marshall Roch
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "ical_builder"
|
8
|
+
gem.summary = %Q{An iCalendar generator in Ruby, modelled after Jim Weirich's Builder}
|
9
|
+
gem.email = "marshall@mroch.com"
|
10
|
+
gem.homepage = "http://github.com/mroch/ical_builder"
|
11
|
+
gem.authors = ["Marshall Roch"]
|
12
|
+
gem.add_dependency 'blankslate'
|
13
|
+
end
|
14
|
+
rescue LoadError
|
15
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'rake/rdoctask'
|
19
|
+
Rake::RDocTask.new do |rdoc|
|
20
|
+
rdoc.rdoc_dir = 'rdoc'
|
21
|
+
rdoc.title = 'ical_builder'
|
22
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
23
|
+
rdoc.rdoc_files.include('README*')
|
24
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
Rake::TestTask.new(:test) do |test|
|
29
|
+
test.libs << 'lib' << 'test'
|
30
|
+
test.pattern = 'test/**/*_test.rb'
|
31
|
+
test.verbose = false
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/*_test.rb'
|
39
|
+
test.verbose = true
|
40
|
+
end
|
41
|
+
rescue LoadError
|
42
|
+
task :rcov do
|
43
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
task :default => :test
|
data/VERSION.yml
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{ical_builder}
|
8
|
+
s.version = "0.2.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Marshall Roch"]
|
12
|
+
s.date = %q{2011-03-28}
|
13
|
+
s.email = %q{marshall@mroch.com}
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"LICENSE",
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"LICENSE",
|
20
|
+
"README.rdoc",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION.yml",
|
23
|
+
"ical_builder.gemspec",
|
24
|
+
"init.rb",
|
25
|
+
"lib/ical_builder.rb",
|
26
|
+
"lib/ical_template.rb",
|
27
|
+
"rails/init.rb",
|
28
|
+
"test/ical_builder_test.rb",
|
29
|
+
"test/test_helper.rb"
|
30
|
+
]
|
31
|
+
s.homepage = %q{http://github.com/mroch/ical_builder}
|
32
|
+
s.require_paths = ["lib"]
|
33
|
+
s.rubygems_version = %q{1.6.2}
|
34
|
+
s.summary = %q{An iCalendar generator in Ruby, modelled after Jim Weirich's Builder}
|
35
|
+
s.test_files = [
|
36
|
+
"test/ical_builder_test.rb",
|
37
|
+
"test/test_helper.rb"
|
38
|
+
]
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
s.specification_version = 3
|
42
|
+
|
43
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
44
|
+
s.add_runtime_dependency(%q<blankslate>, [">= 0"])
|
45
|
+
else
|
46
|
+
s.add_dependency(%q<blankslate>, [">= 0"])
|
47
|
+
end
|
48
|
+
else
|
49
|
+
s.add_dependency(%q<blankslate>, [">= 0"])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
data/init.rb
ADDED
data/lib/ical_builder.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'blankslate'
|
2
|
+
|
3
|
+
module Builder
|
4
|
+
class Ical < BlankSlate
|
5
|
+
def initialize(options = {})
|
6
|
+
@target = options[:target] || ''
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
__fold(@target.to_s)
|
11
|
+
end
|
12
|
+
|
13
|
+
def <<(str)
|
14
|
+
@target << str
|
15
|
+
end
|
16
|
+
|
17
|
+
# RRULE is a special case since it needs to take a hash, but FREQ must
|
18
|
+
# always be first.
|
19
|
+
def rrule(*args)
|
20
|
+
if args[0].is_a?(Hash)
|
21
|
+
freq = __value({ :freq => args[0].delete(:freq) })
|
22
|
+
others = args[0].empty? ? nil : __value(args[0])
|
23
|
+
args[0] = [freq, others].compact.join(';')
|
24
|
+
end
|
25
|
+
method_missing(:rrule, *args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing(sym, *args, &block)
|
29
|
+
value = args.shift
|
30
|
+
if block
|
31
|
+
@target << "BEGIN:#{__property(sym)}\r\n"
|
32
|
+
block.call(self)
|
33
|
+
@target << "END:#{__property(sym)}\r\n"
|
34
|
+
else
|
35
|
+
@target << "#{__property(sym)}#{__parameters(args)}:#{__value(value)}\r\n"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def __property(sym)
|
41
|
+
sym.to_s.upcase.gsub(/_/, '-')
|
42
|
+
end
|
43
|
+
|
44
|
+
# 4.2 Property Parameters
|
45
|
+
def __parameters(args)
|
46
|
+
return '' if args.nil? || args.empty?
|
47
|
+
|
48
|
+
';' + args.collect { |arg|
|
49
|
+
case arg
|
50
|
+
when Hash
|
51
|
+
arg.collect { |k, v| "#{__property(k)}=#{__value(v)}" }.sort.join(';')
|
52
|
+
else
|
53
|
+
arg.to_s
|
54
|
+
end
|
55
|
+
}.join(';')
|
56
|
+
end
|
57
|
+
|
58
|
+
# 4.3 Property Value Data Types
|
59
|
+
def __value(val)
|
60
|
+
case val
|
61
|
+
when Array
|
62
|
+
# 4.1.1
|
63
|
+
val.collect { |v| __value(v) }.join(',')
|
64
|
+
when Hash
|
65
|
+
# 4.1.1
|
66
|
+
val.collect { |k, v| "#{__property(k)}=#{__value(v)}" }.sort.join(';')
|
67
|
+
when true, false
|
68
|
+
# 4.3.2
|
69
|
+
val.to_s.upcase
|
70
|
+
when Date
|
71
|
+
# 4.3.4
|
72
|
+
val.strftime('%Y%m%d')
|
73
|
+
when Time
|
74
|
+
# 4.3.5
|
75
|
+
val.strftime('%Y%m%dT%H%M%S' + (val.utc? ? 'Z' : ''))
|
76
|
+
else
|
77
|
+
val.to_s
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# 4.1 Content Lines
|
82
|
+
def __fold(str)
|
83
|
+
str.split("\r\n").collect { |line| __fold_line(line) }.join("\r\n") + "\r\n"
|
84
|
+
end
|
85
|
+
|
86
|
+
def __fold_line(line)
|
87
|
+
if line.length > 75
|
88
|
+
line[0..74] + "\r\n" + __fold_line(" " + line[75..-1])
|
89
|
+
else
|
90
|
+
line
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Builder
|
2
|
+
class IcalPlugin < ActionView::TemplateHandler
|
3
|
+
include ActionView::TemplateHandlers::Compilable if defined?(ActionView::TemplateHandlers::Compilable)
|
4
|
+
|
5
|
+
def compile(template)
|
6
|
+
"_set_controller_content_type(Mime::ICS);" +
|
7
|
+
"cal = ::Builder::Ical.new;" +
|
8
|
+
"self.output_buffer = cal.to_s;" +
|
9
|
+
template.source +
|
10
|
+
";cal.to_s;"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ActionView::Template.register_template_handler(:ical, Builder::IcalPlugin)
|
17
|
+
ActionView::Template.exempt_from_layout(:ical)
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Kernel.load File.join(File.dirname(__FILE__), '..', 'init.rb')
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class IcalBuilderTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@builder = Builder::Ical.new
|
7
|
+
end
|
8
|
+
|
9
|
+
should "handle boolean property values (4.3.2)" do
|
10
|
+
@builder.gibberish(true)
|
11
|
+
assert_equal "GIBBERISH:TRUE\r\n", @builder.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
should "handle date property values (4.3.4)" do
|
15
|
+
@builder.gibberish(Date.new(2009, 9, 11))
|
16
|
+
assert_equal "GIBBERISH:20090911\r\n", @builder.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
should "handle date-time property values (4.3.5)" do
|
20
|
+
# Local time after 12pm
|
21
|
+
@builder.gibberish(Time.local(2009, 9, 11, 13, 45, 22))
|
22
|
+
assert_equal "GIBBERISH:20090911T134522\r\n", @builder.to_s
|
23
|
+
|
24
|
+
# Local time before 12pm
|
25
|
+
@builder = Builder::Ical.new
|
26
|
+
@builder.gibberish(Time.local(2009, 9, 11, 1, 45, 22))
|
27
|
+
assert_equal "GIBBERISH:20090911T014522\r\n", @builder.to_s
|
28
|
+
|
29
|
+
# UTC after 12pm
|
30
|
+
@builder = Builder::Ical.new
|
31
|
+
@builder.gibberish(Time.utc(2009, 9, 11, 13, 45, 22))
|
32
|
+
assert_equal "GIBBERISH:20090911T134522Z\r\n", @builder.to_s
|
33
|
+
|
34
|
+
# UTC before 12pm
|
35
|
+
@builder = Builder::Ical.new
|
36
|
+
@builder.gibberish(Time.utc(2009, 9, 11, 1, 45, 22))
|
37
|
+
assert_equal "GIBBERISH:20090911T014522Z\r\n", @builder.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
should "handle lists of values (4.1.1)" do
|
41
|
+
@builder.gibberish(['foo', 'bar'])
|
42
|
+
assert_equal "GIBBERISH:foo,bar\r\n", @builder.to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
should "handle lists of values with only one item (4.1.1)" do
|
46
|
+
@builder.gibberish(['foo'])
|
47
|
+
assert_equal "GIBBERISH:foo\r\n", @builder.to_s
|
48
|
+
end
|
49
|
+
|
50
|
+
should "allow newlines (4.3.11)" do
|
51
|
+
@builder.text("Foo bar\nBaz bliffl")
|
52
|
+
assert_equal "TEXT:Foo bar\nBaz bliffl\r\n", @builder.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
should "handle values with multiple parts (4.1.1)" do
|
56
|
+
@builder.gibberish({ :foo => 'bar', :bymonth => 11, :byday => '1SU' })
|
57
|
+
assert_equal "GIBBERISH:BYDAY=1SU;BYMONTH=11;FOO=bar\r\n", @builder.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
should "handle values and properties with multiple values" do
|
61
|
+
@builder.gibberish({ :freq => 'YEARLY', :bymonth => 11, :byday => '1SU' }, { :foo => 'bar', :baz => 'bliffl' })
|
62
|
+
assert_equal "GIBBERISH;BAZ=bliffl;FOO=bar:BYDAY=1SU;BYMONTH=11;FREQ=YEARLY\r\n", @builder.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
should "format parameters without double-quotes correctly" do
|
66
|
+
@builder.organizer('MAILTO:jsmith@host.com', :cn => 'John Smith')
|
67
|
+
assert_equal "ORGANIZER;CN=John Smith:MAILTO:jsmith@host.com\r\n", @builder.to_s
|
68
|
+
end
|
69
|
+
|
70
|
+
should "format parameters with double-quotes correctly" do
|
71
|
+
@builder.organizer('MAILTO:jsmith@host.com', :cn => '"John Smith"')
|
72
|
+
assert_equal "ORGANIZER;CN=\"John Smith\":MAILTO:jsmith@host.com\r\n", @builder.to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
should "format parameters with dashes correctly" do
|
76
|
+
@builder.attendee('MAILTO: jdoe@host.com', :delegated_from => '"MAILTO:jsmith@host.com"')
|
77
|
+
assert_equal \
|
78
|
+
"ATTENDEE;DELEGATED-FROM=\"MAILTO:jsmith@host.com\":MAILTO: jdoe@host.com\r\n",
|
79
|
+
@builder.to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
should "format parameters with multiple values correctly" do
|
83
|
+
@builder.attendee(
|
84
|
+
'MAILTO:janedoe@host.com',
|
85
|
+
:member => ['"MAILTO:projectA@host.com"', '"MAILTO:projectB@host.com"']
|
86
|
+
)
|
87
|
+
assert_equal \
|
88
|
+
"ATTENDEE;MEMBER=\"MAILTO:projectA@host.com\",\"MAILTO:projectB@host.com\":MAILT\r\n O:janedoe@host.com\r\n",
|
89
|
+
@builder.to_s
|
90
|
+
end
|
91
|
+
|
92
|
+
should "append arbitrary text" do
|
93
|
+
@builder.foo("bar")
|
94
|
+
@builder << "ARBITRARY-PROPERTY:\"Lorem ipsum dolor sit amet\"\r\n"
|
95
|
+
assert_equal "FOO:bar\r\nARBITRARY-PROPERTY:\"Lorem ipsum dolor sit amet\"\r\n", @builder.to_s
|
96
|
+
end
|
97
|
+
|
98
|
+
should "not fold lines less than 75 characters long" do
|
99
|
+
@builder.text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
|
100
|
+
assert_equal "TEXT:Lorem ipsum dolor sit amet, consectetur adipiscing elit.\r\n", @builder.to_s
|
101
|
+
end
|
102
|
+
|
103
|
+
should "not fold lines exactly 75 characters long" do
|
104
|
+
@builder.text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nullam.")
|
105
|
+
assert_equal "TEXT:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nullam.\r\n", @builder.to_s
|
106
|
+
end
|
107
|
+
|
108
|
+
should "not fold lines exactly 75 characters long even if they end in whitespace" do
|
109
|
+
@builder.text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nullam ")
|
110
|
+
assert_equal "TEXT:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nullam \r\n", @builder.to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
should "fold lines longer than 75 characters" do
|
114
|
+
@builder.description("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget elit tellus. In hac habitasse platea dictumst. Vestibulum tincidunt velit id erat interdum id tristique diam blandit. Praesent nullam.")
|
115
|
+
assert_equal \
|
116
|
+
"DESCRIPTION:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eg\r\n et elit tellus. In hac habitasse platea dictumst. Vestibulum tincidunt vel\r\n it id erat interdum id tristique diam blandit. Praesent nullam.\r\n",
|
117
|
+
@builder.to_s
|
118
|
+
end
|
119
|
+
|
120
|
+
should "fold lines longer than 75 characters even if only whitespace" do
|
121
|
+
@builder.text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nullam. ")
|
122
|
+
assert_equal "TEXT:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nullam.\r\n \r\n", @builder.to_s
|
123
|
+
end
|
124
|
+
|
125
|
+
should "fold arbitrary text" do
|
126
|
+
@builder << "TEXT:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget elit tellus. In hac habitasse platea dictumst.\r\n"
|
127
|
+
assert_equal "TEXT:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget elit\r\n tellus. In hac habitasse platea dictumst.\r\n", @builder.to_s
|
128
|
+
end
|
129
|
+
|
130
|
+
should "always place FREQ first in RRULE values" do
|
131
|
+
@builder.rrule({ :freq => 'YEARLY', :interval => 1, :byday => '1SU' })
|
132
|
+
assert_equal "RRULE:FREQ=YEARLY;BYDAY=1SU;INTERVAL=1\r\n", @builder.to_s
|
133
|
+
end
|
134
|
+
|
135
|
+
should "format RRULEs properly even with only FREQ" do
|
136
|
+
@builder.rrule({ :freq => 'YEARLY' })
|
137
|
+
assert_equal "RRULE:FREQ=YEARLY\r\n", @builder.to_s
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ical_builder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 21
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Marshall Roch
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-03-28 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: blankslate
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description:
|
36
|
+
email: marshall@mroch.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- LICENSE
|
46
|
+
- README.rdoc
|
47
|
+
- Rakefile
|
48
|
+
- VERSION.yml
|
49
|
+
- ical_builder.gemspec
|
50
|
+
- init.rb
|
51
|
+
- lib/ical_builder.rb
|
52
|
+
- lib/ical_template.rb
|
53
|
+
- rails/init.rb
|
54
|
+
- test/ical_builder_test.rb
|
55
|
+
- test/test_helper.rb
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: http://github.com/mroch/ical_builder
|
58
|
+
licenses: []
|
59
|
+
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 3
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.3.7
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: An iCalendar generator in Ruby, modelled after Jim Weirich's Builder
|
90
|
+
test_files:
|
91
|
+
- test/ical_builder_test.rb
|
92
|
+
- test/test_helper.rb
|