vobject 1.0.2

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 (49) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/macos.yml +38 -0
  3. data/.github/workflows/ubuntu.yml +56 -0
  4. data/.github/workflows/windows.yml +40 -0
  5. data/.gitignore +9 -0
  6. data/.hound.yml +3 -0
  7. data/.rspec +2 -0
  8. data/.rubocop.tb.yml +650 -0
  9. data/.rubocop.yml +1077 -0
  10. data/CODE_OF_CONDUCT.md +49 -0
  11. data/Gemfile +4 -0
  12. data/LICENSE.txt +25 -0
  13. data/README.adoc +151 -0
  14. data/Rakefile +6 -0
  15. data/bin/console +14 -0
  16. data/bin/setup +8 -0
  17. data/lib/c.rb +173 -0
  18. data/lib/error.rb +19 -0
  19. data/lib/vcalendar.rb +77 -0
  20. data/lib/vcard.rb +67 -0
  21. data/lib/vobject.rb +25 -0
  22. data/lib/vobject/component.rb +126 -0
  23. data/lib/vobject/parameter.rb +116 -0
  24. data/lib/vobject/parametervalue.rb +26 -0
  25. data/lib/vobject/property.rb +162 -0
  26. data/lib/vobject/propertyvalue.rb +46 -0
  27. data/lib/vobject/vcalendar/component.rb +106 -0
  28. data/lib/vobject/vcalendar/grammar.rb +595 -0
  29. data/lib/vobject/vcalendar/paramcheck.rb +259 -0
  30. data/lib/vobject/vcalendar/propertyparent.rb +98 -0
  31. data/lib/vobject/vcalendar/propertyvalue.rb +606 -0
  32. data/lib/vobject/vcalendar/typegrammars.rb +605 -0
  33. data/lib/vobject/vcard/v3_0/component.rb +40 -0
  34. data/lib/vobject/vcard/v3_0/grammar.rb +175 -0
  35. data/lib/vobject/vcard/v3_0/paramcheck.rb +110 -0
  36. data/lib/vobject/vcard/v3_0/parameter.rb +17 -0
  37. data/lib/vobject/vcard/v3_0/property.rb +18 -0
  38. data/lib/vobject/vcard/v3_0/propertyvalue.rb +401 -0
  39. data/lib/vobject/vcard/v3_0/typegrammars.rb +425 -0
  40. data/lib/vobject/vcard/v4_0/component.rb +40 -0
  41. data/lib/vobject/vcard/v4_0/grammar.rb +224 -0
  42. data/lib/vobject/vcard/v4_0/paramcheck.rb +269 -0
  43. data/lib/vobject/vcard/v4_0/parameter.rb +18 -0
  44. data/lib/vobject/vcard/v4_0/property.rb +63 -0
  45. data/lib/vobject/vcard/v4_0/propertyvalue.rb +404 -0
  46. data/lib/vobject/vcard/v4_0/typegrammars.rb +539 -0
  47. data/lib/vobject/version.rb +3 -0
  48. data/vobject.gemspec +32 -0
  49. metadata +174 -0
@@ -0,0 +1,77 @@
1
+ require "vobject"
2
+ require "vobject/component"
3
+ require "vobject/vcalendar/component"
4
+ require "vobject/vcalendar/grammar"
5
+ require "json"
6
+
7
+ class Vcalendar < Vobject::Component
8
+ attr_accessor :comp_name, :children, :version
9
+
10
+ class << self
11
+ def parse(vcf, strict)
12
+ Vobject::Component::Vcalendar.parse(vcf, strict)
13
+ end
14
+ end
15
+
16
+ def initialize(key, cs, err)
17
+ super key, cs, err
18
+ end
19
+
20
+ def child_class(key, val)
21
+ base_class = if key == :VTODO
22
+ Vobject::Component::Vcalendar::ToDo
23
+ elsif key == :VFREEBUSY
24
+ Vobject::Component::Vcalendar::FreeBusy
25
+ elsif key == :JOURNAL
26
+ Vobject::Component::Vcalendar::Journal
27
+ elsif key == :STANDARD
28
+ Vobject::Component::Vcalendar::Timezone::Standard
29
+ elsif key == :DAYLIGHT
30
+ Vobject::Component::Vcalendar::Timezone::Daylight
31
+ elsif key == :VTIMEZONE
32
+ Vobject::Component::Vcalendar::Timezone
33
+ elsif key == :VEVENT
34
+ Vobject::Component::Vcalendar::Event
35
+ elsif key == :VALARM
36
+ Vobject::Component::Vcalendar::Alarm
37
+ elsif key == :VAVAILABILITY
38
+ Vobject::Component::Vcalendar::Vavailability
39
+ elsif key == :AVAILABLE
40
+ Vobject::Component::Vcalendar::Vavailability::Available
41
+ elsif !(val.is_a?(Hash) && !val.has_key?(:value))
42
+ property_base_class
43
+ else
44
+ Vobject::Component::Vcalendar
45
+ end
46
+ return base_class if [:CLASS, :OBJECT, :METHOD].include?
47
+ camelized_key = key.to_s.downcase.split("_").map(&:capitalize).join("")
48
+ base_class.const_get(camelized_key) rescue base_class
49
+ end
50
+
51
+ private
52
+
53
+ def raise_invalid_parsing
54
+ raise "Vobject component parse failed"
55
+ end
56
+ end
57
+
58
+ class Vobject::Component::Vcalendar::ToDo < Vobject::Component::Vcalendar
59
+ end
60
+ class Vobject::Component::Vcalendar::Freebusy < Vobject::Component::Vcalendar
61
+ end
62
+ class Vobject::Component::Vcalendar::Journal < Vobject::Component::Vcalendar
63
+ end
64
+ class Vobject::Component::Vcalendar::Timezone < Vobject::Component::Vcalendar
65
+ end
66
+ class Vobject::Component::Vcalendar::Timezone::Standard < Vobject::Component::Vcalendar::Timezone
67
+ end
68
+ class Vobject::Component::Vcalendar::Timezone::Daylight < Vobject::Component::Vcalendar::Timezone
69
+ end
70
+ class Vobject::Component::Vcalendar::Event < Vobject::Component::Vcalendar
71
+ end
72
+ class Vobject::Component::Vcalendar::Alarm < Vobject::Component::Vcalendar
73
+ end
74
+ class Vobject::Component::Vcalendar::Vavailability < Vobject::Component::Vcalendar
75
+ end
76
+ # class Vobject::Component::Vcalendar::Vavailability::Available < Vobject::Component::Vcalendar::Vavailability
77
+ # end
@@ -0,0 +1,67 @@
1
+ require "vobject"
2
+ require "vobject/component"
3
+
4
+ class Vcard < Vobject::Component
5
+ attr_accessor :version
6
+
7
+ class << self
8
+ def blank(version)
9
+ new VERSION: { value: version }
10
+ end
11
+
12
+ def decode(vcard_str, version = nil)
13
+ version_str = version.nil? ? "4.0" : /\nVERSION:([^\n\r]+)/i.match(vcard_str)[1]
14
+ blank(version_str).parse(vcard_str)
15
+ end
16
+
17
+ def parse(vcf, version, strict)
18
+ hash = version == "3.0" ? Vcard::V3_0::Component.parse(vcf, strict) : Vcard::V4_0::Component.parse(vcf, strict)
19
+ # comp_name = hash.keys.first
20
+ # return self.new(comp_name, hash[:vobject][comp_name], hash[:errors] )
21
+ hash
22
+ end
23
+
24
+ private
25
+
26
+ def raise_invalid_parsing
27
+ raise "vCard parse failed"
28
+ end
29
+ end
30
+
31
+ def initialize(version)
32
+ self.version = version
33
+ super VCARD: { VERSION: { value: version } }
34
+ end
35
+
36
+ private
37
+
38
+ def name
39
+ :VCARD
40
+ end
41
+
42
+ def property_base_class
43
+ version == "3.0" ? Vcard::V3_0::Property : Vcard::V4_0::Property
44
+ # version_class.const_get(:Property)
45
+ end
46
+
47
+ def component_base_class
48
+ version == "3.0" ? Vcard::V3_0::Component : Vcard::V4_0::Component
49
+ # version_class.const_get(:Component)
50
+ end
51
+ end
52
+
53
+ def require_dir(dir)
54
+ base = File.expand_path("../", __FILE__)
55
+ Dir.glob(File.join(base, dir, "**", "*.rb")).each do |path|
56
+ require path.gsub(/\.rb\Z/, "")
57
+ end
58
+ end
59
+
60
+ require "vobject/vcard/v4_0/component"
61
+ require "vobject/vcard/v4_0/property"
62
+ require_dir "vobject/vcard/v4_0/component"
63
+ require_dir "vobject/vcard/v4_0/property"
64
+ require "vobject/vcard/v3_0/component"
65
+ require "vobject/vcard/v3_0/property"
66
+ require_dir "vobject/vcard/v3_0/component"
67
+ require_dir "vobject/vcard/v3_0/property"
@@ -0,0 +1,25 @@
1
+ module Vobject
2
+ class << self
3
+ MAX_LINE_WIDTH = 75
4
+ def unfold(str)
5
+ str.gsub(/(\r|\n|\r\n)[ \t]/, "")
6
+ end
7
+
8
+ # This implements the line folding as specified in
9
+ # http://tools.ietf.org/html/rfc6350#section-3.2
10
+ # NOTE: the "line" here is not including the trailing \n
11
+ def fold_line(line)
12
+ folded_line = line[0, MAX_LINE_WIDTH]
13
+ remainder_line = line[MAX_LINE_WIDTH, line.length - MAX_LINE_WIDTH] || ""
14
+
15
+ max_width = MAX_LINE_WIDTH - 1
16
+
17
+ (0..((remainder_line.length - 1) / max_width)).each do |i|
18
+ folded_line << "\n "
19
+ folded_line << remainder_line[i * max_width, max_width]
20
+ end
21
+
22
+ folded_line
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,126 @@
1
+ require "vobject"
2
+ require "vobject/property"
3
+ require "vobject/vcalendar/grammar"
4
+ require "json"
5
+
6
+ class Vobject::Component
7
+ attr_accessor :comp_name, :children, :multiple_components, :errors, :norm
8
+
9
+ def <=>(another)
10
+ me = self.to_norm
11
+ o = another.to_norm
12
+ me <=> o
13
+ end
14
+
15
+ def blank(version)
16
+ ingest VOBJECT: { VERSION: { value: version } }
17
+ end
18
+
19
+ def initialize(key, cs, err)
20
+ self.comp_name = key
21
+ raise_invalid_initialization if key != name
22
+ self.children = []
23
+ if cs.nil?
24
+ else
25
+ cs.each_key do |k|
26
+ val = cs[k]
27
+ # iteration of array || hash values is making the value a key!
28
+ next if k.class == Array
29
+ next if k.class == Hash
30
+ cc = child_class(k, val)
31
+ if val.is_a?(Hash) && val.has_key?(:component)
32
+ val[:component].each do |x|
33
+ children << cc.new(k, x, [])
34
+ end
35
+ else
36
+ children << cc.new(k, val)
37
+ end
38
+ end
39
+ end
40
+ self.errors = err.select { |e| !e.nil? }
41
+ self.norm = nil
42
+ end
43
+
44
+ def get_errors
45
+ errors
46
+ end
47
+
48
+ def child_class(key, val)
49
+ base_class = if val.is_a?(Hash) && val.has_key?(:component)
50
+ component_base_class
51
+ elsif !(val.is_a?(Hash) && !val.has_key?(:value))
52
+ property_base_class
53
+ else
54
+ component_base_class
55
+ end
56
+ return base_class if [:CLASS, :OBJECT, :METHOD].include? key
57
+ camelized_key = key.to_s.downcase.split("_").map(&:capitalize).join("")
58
+ base_class.const_get(camelized_key) rescue base_class
59
+ end
60
+
61
+ def to_s
62
+ s = "BEGIN:#{name}\n"
63
+ children.each do |c|
64
+ s << c.to_s
65
+ end
66
+ s << "END:#{name}\n"
67
+ s
68
+ end
69
+
70
+ def to_norm
71
+ if norm.nil?
72
+ s = "BEGIN:#{name.upcase}\n"
73
+ properties = children.select { |c| c.is_a? Vobject::Property }
74
+ components = children.select { |c| not c.is_a? Vobject::Property }
75
+ # create to_norm in advance
76
+ properties.each { |p| p.to_norm }
77
+ properties.sort.each do |p|
78
+ s << p.to_norm
79
+ end
80
+ components.sort.each { |p| s << p.to_norm }
81
+ s << "END:#{name.upcase}\n"
82
+ norm = s
83
+ end
84
+ norm
85
+ end
86
+
87
+ def to_hash
88
+ a = {}
89
+ children.each do |c|
90
+ if c.is_a?(Vobject::Component)
91
+ a = a.merge(c.to_hash) { |_, old, new| [old, new].flatten }
92
+ elsif c.is_a?(Vobject::Property)
93
+ a = a.merge(c.to_hash) { |_, old, new| [old, new].flatten }
94
+ else
95
+ a[c.name] = c.to_hash
96
+ end
97
+ end
98
+ { comp_name => a }
99
+ end
100
+
101
+ def to_json
102
+ to_hash.to_json
103
+ end
104
+
105
+ def name
106
+ comp_name
107
+ end
108
+
109
+ private
110
+
111
+ def property_base_class
112
+ Vobject::Property
113
+ end
114
+
115
+ def component_base_class
116
+ Vobject::Component
117
+ end
118
+
119
+ def parameter_base_class
120
+ Vobject::Parameter
121
+ end
122
+
123
+ def raise_invalid_initialization
124
+ raise "vObject component initialization failed"
125
+ end
126
+ end
@@ -0,0 +1,116 @@
1
+ module Vobject
2
+ class Parameter
3
+ attr_accessor :param_name, :value, :multiple, :norm
4
+
5
+ def <=>(another)
6
+ self.to_norm <=> another.to_norm
7
+ end
8
+
9
+ def initialize(key, options)
10
+ self.param_name = key
11
+ if options.class == Array
12
+ self.multiple = []
13
+ options.each do |v|
14
+ multiple << parameter_base_class.new(key, v)
15
+ self.param_name = key
16
+ end
17
+ else
18
+ self.value = options
19
+ end
20
+ norm = nil
21
+ raise_invalid_initialization(key, name) if key != name
22
+ end
23
+
24
+ def to_s
25
+ # we made param names have underscore instead of dash as symbols
26
+ line = param_name.to_s.tr("_", "-")
27
+ line << "="
28
+ if multiple
29
+ arr = []
30
+ multiple.each { |v| arr << to_s_line(v.value.to_s) }
31
+ line << arr.join(",")
32
+ else
33
+ line << to_s_line(value.to_s)
34
+ end
35
+ line
36
+ end
37
+
38
+ def to_s_line(val)
39
+ # RFC 6868
40
+ val = val.to_s.gsub(/\^/, "^^").gsub(/\n/, "^n").gsub(/"/, "^'")
41
+ if val =~ /[:;,]/
42
+ val = '"' + val + '"'
43
+ end
44
+ val
45
+ end
46
+
47
+ def to_norm
48
+ if norm.nil?
49
+ line = param_name.to_s.tr("_", "-").upcase
50
+ line << "="
51
+ if multiple
52
+ arr = []
53
+ multiple.sort.each { |v| arr << to_norm_line(v.value) }
54
+ line << arr.join(",")
55
+ else
56
+ line << to_norm_line(value)
57
+ end
58
+ norm = line
59
+ end
60
+ norm
61
+ end
62
+
63
+ def to_norm_line(val)
64
+ # RFC 6868
65
+ val = val.to_s.gsub(/\^/, "^^").gsub(/\n/, "^n").gsub(/"/, "^'")
66
+ #if val =~ /[:;,]/
67
+ val = '"' + val + '"'
68
+ #end
69
+ val
70
+ end
71
+
72
+ def to_hash
73
+ if multiple
74
+ val = []
75
+ multiple.each do |c|
76
+ val << c.value
77
+ end
78
+ { param_name => val }
79
+ else
80
+ { param_name => value }
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def name
87
+ param_name
88
+ end
89
+
90
+ def parse_value(value)
91
+ parse_method = :"parse_#{value_type}_value"
92
+ parse_method = respond_to?(parse_method, true) ? parse_method : :parse_text_value
93
+ send(parse_method, value)
94
+ end
95
+
96
+ def parse_text_value(value)
97
+ value
98
+ end
99
+
100
+ def value_type
101
+ (params || {})[:VALUE] || default_value_type
102
+ end
103
+
104
+ def default_value_type
105
+ "text"
106
+ end
107
+
108
+ def parameter_base_class
109
+ Vobject::Parameter
110
+ end
111
+
112
+ def raise_invalid_initialization(key, name)
113
+ raise "vObject property initialization failed (#{key}, #{name})"
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,26 @@
1
+ module Vobject
2
+ class ParameterValue
3
+ def initialize(val)
4
+ self.value = val
5
+ end
6
+ # raise_invalid_initialization if key != name
7
+ end
8
+
9
+ def to_s
10
+ value
11
+ end
12
+
13
+ private
14
+
15
+ def name
16
+ prop_name
17
+ end
18
+
19
+ def default_value_type
20
+ "text"
21
+ end
22
+
23
+ def raise_invalid_initialization
24
+ raise "vObject property initialization failed"
25
+ end
26
+ end
@@ -0,0 +1,162 @@
1
+ require "vobject"
2
+ require "vobject/parameter"
3
+
4
+ class Vobject::Property
5
+ attr_accessor :group, :prop_name, :params, :value, :multiple, :norm
6
+
7
+ def <=>(another)
8
+ if self.prop_name =~ /^VERSION$/i
9
+ -1
10
+ elsif another.prop_name =~ /^VERSION$/i
11
+ 1
12
+ else
13
+ self.to_norm <=> another.to_norm
14
+ end
15
+ end
16
+
17
+ def initialize(key, options)
18
+ if options.class == Array
19
+ self.multiple = []
20
+ options.each do |v|
21
+ multiple << property_base_class.new(key, v)
22
+ self.prop_name = key
23
+ end
24
+ else
25
+ self.prop_name = key
26
+ if options.nil? || options.empty?
27
+ self.group = nil
28
+ self.params = []
29
+ self.value = nil
30
+ else
31
+ self.group = options[:group]
32
+ self.prop_name = key
33
+ unless options[:params].nil? || options[:params].empty?
34
+ self.params = []
35
+ options[:params].each do |k, v|
36
+ params << parameter_base_class.new(k, v)
37
+ end
38
+ end
39
+ # self.value = parse_value(options[:value])
40
+ self.value = options[:value]
41
+ end
42
+ end
43
+ self.norm = nil
44
+ raise_invalid_initialization if key != name
45
+ end
46
+
47
+ def to_s
48
+ if multiple.nil? || multiple.empty?
49
+ ret = to_s_line
50
+ else
51
+ arr = []
52
+ multiple.each do |x|
53
+ arr << x.to_s_line
54
+ end
55
+ ret = arr.join("")
56
+ end
57
+ ret
58
+ end
59
+
60
+ def to_s_line
61
+ line = group ? "#{group}." : ""
62
+ line << name.to_s.tr("_", "-")
63
+
64
+ (params || {}).each do |p|
65
+ line << ";#{p}"
66
+ end
67
+
68
+ line << ":#{value}"
69
+
70
+ line = Vobject::fold_line(line) << "\n"
71
+
72
+ line
73
+ end
74
+
75
+ def to_norm
76
+ if @norm.nil?
77
+ if multiple.nil? || multiple.empty?
78
+ ret = to_norm_line
79
+ else
80
+ arr = []
81
+ multiple.sort.each do |x|
82
+ arr << x.to_norm_line
83
+ end
84
+ ret = arr.join("")
85
+ end
86
+ @norm = ret
87
+ end
88
+ @norm
89
+ end
90
+
91
+ def to_norm_line
92
+ line = group ? "#{group}." : ""
93
+ line << name.to_s.tr("_", "-").upcase
94
+
95
+ (params || {}).sort.each do |p|
96
+ line << ";#{p.to_norm}"
97
+ end
98
+
99
+ line << ":#{value.to_norm}"
100
+
101
+ line = Vobject::fold_line(line) << "\n"
102
+
103
+ line
104
+ end
105
+
106
+
107
+ def to_hash
108
+ ret = {}
109
+ if multiple
110
+ ret[prop_name] = []
111
+ multiple.each do |c|
112
+ ret[prop_name] = ret[prop_name] << c.to_hash[prop_name]
113
+ end
114
+ else
115
+ ret = {prop_name => { value: value.to_hash } }
116
+ ret[prop_name][:group] = group unless group.nil?
117
+ if params
118
+ ret[prop_name][:params] = {}
119
+ params.each do |p|
120
+ ret[prop_name][:params] = ret[prop_name][:params].merge p.to_hash
121
+ end
122
+ end
123
+ end
124
+ ret
125
+ end
126
+
127
+ private
128
+
129
+ def name
130
+ prop_name
131
+ end
132
+
133
+ def parse_value(value)
134
+ parse_method = :"parse_#{value_type}_value"
135
+ parse_method = respond_to?(parse_method, true) ? parse_method : :parse_text_value
136
+ send(parse_method, value)
137
+ end
138
+
139
+ def parse_text_value(value)
140
+ value
141
+ end
142
+
143
+ def value_type
144
+ params ? params[0].value : default_value_type
145
+ end
146
+
147
+ def default_value_type
148
+ "text"
149
+ end
150
+
151
+ def property_base_class
152
+ Vobject::Property
153
+ end
154
+
155
+ def parameter_base_class
156
+ Vobject::Parameter
157
+ end
158
+
159
+ def raise_invalid_initialization
160
+ raise "vObject property initialization failed"
161
+ end
162
+ end