cloud_events 0.7.1 → 0.8.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +4 -0
- data/lib/cloud_events/content_type.rb +32 -32
- data/lib/cloud_events/event/field_interpreter.rb +46 -38
- data/lib/cloud_events/event/opaque.rb +3 -3
- data/lib/cloud_events/event/utils.rb +9 -9
- data/lib/cloud_events/event/v0.rb +19 -19
- data/lib/cloud_events/event/v1.rb +21 -21
- data/lib/cloud_events/event.rb +4 -4
- data/lib/cloud_events/format.rb +13 -14
- data/lib/cloud_events/http_binding.rb +88 -88
- data/lib/cloud_events/json_format.rb +65 -66
- data/lib/cloud_events/text_format.rb +6 -7
- data/lib/cloud_events/version.rb +1 -1
- metadata +6 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e92a0db6d57da2784f958e81f3416ade3c4c6c1e5e7830571be444c84a1001a0
|
|
4
|
+
data.tar.gz: e48bad4cf6cf8797c6f5a16817f6951a1c3b2138778fa2e6779b58fd49f28f21
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4429473d95e6150514f796a907f74a96741ab9378e2c833ed6945fbe4f5d85fe654d0bb6502960900c349721b167f90fc62994a2525a3fd372bc7ea9468c66f6
|
|
7
|
+
data.tar.gz: 91f22bf6c0b20357326166d896e0036dd90ae32f66b7c233a63cb3e060abac51827b2a9d560f6324830db2b5240e436d0f942c99a41bf8a1c711a48fe6af8d80
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
### v0.8.0 / 2025-11-04
|
|
4
|
+
|
|
5
|
+
* BREAKING CHANGE: Raise AttributeError if an illegal attribute name is used
|
|
6
|
+
* ADDED: Require Ruby 2.7 or later
|
|
7
|
+
* FIXED: Improved hashing algorithm for opaque event objects
|
|
8
|
+
* FIXED: Removed dependency on base64 gem
|
|
9
|
+
* FIXED: Raise AttributeError if an illegal attribute name is used
|
|
10
|
+
* DOCS: Add link to the security mailing list
|
|
11
|
+
|
|
3
12
|
### v0.7.1 / 2023-10-04
|
|
4
13
|
|
|
5
14
|
* DOCS: Governance docs per CE PR 1226
|
data/README.md
CHANGED
|
@@ -218,6 +218,10 @@ for how PR reviews and approval, and our
|
|
|
218
218
|
[Code of Conduct](https://github.com/cloudevents/spec/blob/master/community/GOVERNANCE.md#additional-information)
|
|
219
219
|
information.
|
|
220
220
|
|
|
221
|
+
If there is a security concern with one of the CloudEvents specifications, or
|
|
222
|
+
with one of the project's SDKs, please send an email to
|
|
223
|
+
[cncf-cloudevents-security@lists.cncf.io](mailto:cncf-cloudevents-security@lists.cncf.io).
|
|
224
|
+
|
|
221
225
|
## Additional SDK Resources
|
|
222
226
|
|
|
223
227
|
- [List of current active maintainers](MAINTAINERS.md)
|
|
@@ -24,7 +24,7 @@ module CloudEvents
|
|
|
24
24
|
# @param default_charset [String] Optional. The charset to use if none is
|
|
25
25
|
# specified. Defaults to `us-ascii`.
|
|
26
26
|
#
|
|
27
|
-
def initialize
|
|
27
|
+
def initialize(string, default_charset: nil)
|
|
28
28
|
@string = string.to_s
|
|
29
29
|
@media_type = "text"
|
|
30
30
|
@subtype_base = @subtype = "plain"
|
|
@@ -32,9 +32,9 @@ module CloudEvents
|
|
|
32
32
|
@params = []
|
|
33
33
|
@charset = default_charset || "us-ascii"
|
|
34
34
|
@error_message = nil
|
|
35
|
-
parse
|
|
35
|
+
parse(consume_comments(@string.strip))
|
|
36
36
|
@canonical_string = "#{@media_type}/#{@subtype}" +
|
|
37
|
-
@params.map { |k, v| "; #{k}=#{maybe_quote
|
|
37
|
+
@params.map { |k, v| "; #{k}=#{maybe_quote(v)}" }.join
|
|
38
38
|
full_freeze
|
|
39
39
|
end
|
|
40
40
|
|
|
@@ -102,13 +102,13 @@ module CloudEvents
|
|
|
102
102
|
# @param key [String]
|
|
103
103
|
# @return [Array<String>]
|
|
104
104
|
#
|
|
105
|
-
def param_values
|
|
105
|
+
def param_values(key)
|
|
106
106
|
key = key.downcase
|
|
107
107
|
@params.inject([]) { |a, (k, v)| key == k ? a << v : a }
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
## @private
|
|
111
|
-
def ==
|
|
111
|
+
def ==(other)
|
|
112
112
|
other.is_a?(ContentType) && canonical_string == other.canonical_string
|
|
113
113
|
end
|
|
114
114
|
alias eql? ==
|
|
@@ -124,16 +124,16 @@ module CloudEvents
|
|
|
124
124
|
|
|
125
125
|
private
|
|
126
126
|
|
|
127
|
-
def parse
|
|
128
|
-
@media_type, str = consume_token
|
|
129
|
-
str = consume_special
|
|
130
|
-
@subtype, str = consume_token
|
|
131
|
-
@subtype_base, @subtype_format = @subtype.split
|
|
127
|
+
def parse(str)
|
|
128
|
+
@media_type, str = consume_token(str, downcase: true, error_message: "Failed to parse media type")
|
|
129
|
+
str = consume_special(str, "/")
|
|
130
|
+
@subtype, str = consume_token(str, downcase: true, error_message: "Failed to parse subtype")
|
|
131
|
+
@subtype_base, @subtype_format = @subtype.split("+", 2)
|
|
132
132
|
until str.empty?
|
|
133
|
-
str = consume_special
|
|
134
|
-
name, str = consume_token
|
|
135
|
-
str = consume_special
|
|
136
|
-
val, str = consume_token_or_quoted
|
|
133
|
+
str = consume_special(str, ";")
|
|
134
|
+
name, str = consume_token(str, downcase: true, error_message: "Faled to parse attribute name")
|
|
135
|
+
str = consume_special(str, "=", error_message: "Failed to find value for attribute #{name}")
|
|
136
|
+
val, str = consume_token_or_quoted(str, error_message: "Failed to parse value for attribute #{name}")
|
|
137
137
|
@params << [name, val]
|
|
138
138
|
@charset = val if name == "charset"
|
|
139
139
|
end
|
|
@@ -141,34 +141,34 @@ module CloudEvents
|
|
|
141
141
|
@error_message = e.message
|
|
142
142
|
end
|
|
143
143
|
|
|
144
|
-
def consume_token
|
|
145
|
-
match = /^([\w!#$%&'*+.\^`{|}-]+)(.*)$/.match
|
|
146
|
-
raise
|
|
144
|
+
def consume_token(str, downcase: false, error_message: nil)
|
|
145
|
+
match = /^([\w!#$%&'*+.\^`{|}-]+)(.*)$/.match(str)
|
|
146
|
+
raise(ParseError, error_message || "Expected token") unless match
|
|
147
147
|
token = match[1]
|
|
148
148
|
token.downcase! if downcase
|
|
149
|
-
str = consume_comments
|
|
149
|
+
str = consume_comments(match[2].strip)
|
|
150
150
|
[token, str]
|
|
151
151
|
end
|
|
152
152
|
|
|
153
|
-
def consume_special
|
|
154
|
-
raise
|
|
155
|
-
consume_comments
|
|
153
|
+
def consume_special(str, expected, error_message: nil)
|
|
154
|
+
raise(ParseError, error_message || "Expected #{expected.inspect}") unless str.start_with?(expected)
|
|
155
|
+
consume_comments(str[1..].strip)
|
|
156
156
|
end
|
|
157
157
|
|
|
158
|
-
def consume_token_or_quoted
|
|
159
|
-
return consume_token
|
|
158
|
+
def consume_token_or_quoted(str, error_message: nil)
|
|
159
|
+
return consume_token(str) unless str.start_with?('"')
|
|
160
160
|
arr = []
|
|
161
161
|
index = 1
|
|
162
162
|
loop do
|
|
163
163
|
char = str[index]
|
|
164
164
|
case char
|
|
165
165
|
when nil
|
|
166
|
-
raise
|
|
166
|
+
raise(ParseError, error_message || "Quoted-string never finished")
|
|
167
167
|
when "\""
|
|
168
168
|
break
|
|
169
169
|
when "\\"
|
|
170
170
|
char = str[index + 1]
|
|
171
|
-
raise
|
|
171
|
+
raise(ParseError, error_message || "Quoted-string never finished") unless char
|
|
172
172
|
arr << char
|
|
173
173
|
index += 2
|
|
174
174
|
else
|
|
@@ -177,34 +177,34 @@ module CloudEvents
|
|
|
177
177
|
end
|
|
178
178
|
end
|
|
179
179
|
index += 1
|
|
180
|
-
str = consume_comments
|
|
180
|
+
str = consume_comments(str[index..].strip)
|
|
181
181
|
[arr.join, str]
|
|
182
182
|
end
|
|
183
183
|
|
|
184
|
-
def consume_comments
|
|
185
|
-
return str unless str.start_with?
|
|
184
|
+
def consume_comments(str)
|
|
185
|
+
return str unless str.start_with?("(")
|
|
186
186
|
index = 1
|
|
187
187
|
loop do
|
|
188
188
|
char = str[index]
|
|
189
189
|
case char
|
|
190
190
|
when nil
|
|
191
|
-
raise
|
|
191
|
+
raise(ParseError, "Comment never finished")
|
|
192
192
|
when ")"
|
|
193
193
|
break
|
|
194
194
|
when "\\"
|
|
195
195
|
index += 2
|
|
196
196
|
when "("
|
|
197
|
-
str = consume_comments
|
|
197
|
+
str = consume_comments(str[index..])
|
|
198
198
|
index = 0
|
|
199
199
|
else
|
|
200
200
|
index += 1
|
|
201
201
|
end
|
|
202
202
|
end
|
|
203
203
|
index += 1
|
|
204
|
-
consume_comments
|
|
204
|
+
consume_comments(str[index..].strip)
|
|
205
205
|
end
|
|
206
206
|
|
|
207
|
-
def maybe_quote
|
|
207
|
+
def maybe_quote(str)
|
|
208
208
|
return str if /^[\w!#$%&'*+.\^`{|}-]+$/ =~ str
|
|
209
209
|
str = str.gsub("\\", "\\\\\\\\").gsub("\"", "\\\\\"")
|
|
210
210
|
"\"#{str}\""
|
|
@@ -9,60 +9,61 @@ module CloudEvents
|
|
|
9
9
|
# @private
|
|
10
10
|
#
|
|
11
11
|
class FieldInterpreter
|
|
12
|
-
def initialize
|
|
13
|
-
@args = Utils.keys_to_strings
|
|
12
|
+
def initialize(args)
|
|
13
|
+
@args = Utils.keys_to_strings(args)
|
|
14
14
|
@attributes = {}
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def finish_attributes
|
|
17
|
+
def finish_attributes(requires_lc_start: false)
|
|
18
18
|
@args.each do |key, value|
|
|
19
|
+
check_attribute_name(key, requires_lc_start)
|
|
19
20
|
@attributes[key.freeze] = value.to_s.freeze unless value.nil?
|
|
20
21
|
end
|
|
21
22
|
@args = {}
|
|
22
23
|
@attributes.freeze
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
def string
|
|
26
|
-
object
|
|
26
|
+
def string(keys, required: false, allow_empty: false)
|
|
27
|
+
object(keys, required: required) do |value|
|
|
27
28
|
case value
|
|
28
29
|
when ::String
|
|
29
|
-
raise
|
|
30
|
+
raise(AttributeError, "The #{keys.first} field cannot be empty") if value.empty? && !allow_empty
|
|
30
31
|
value.freeze
|
|
31
32
|
[value, value]
|
|
32
33
|
else
|
|
33
|
-
raise
|
|
34
|
-
"
|
|
34
|
+
raise(AttributeError, "Illegal type for #{keys.first}: " \
|
|
35
|
+
"String expected but #{value.class} found")
|
|
35
36
|
end
|
|
36
37
|
end
|
|
37
38
|
end
|
|
38
39
|
|
|
39
|
-
def uri
|
|
40
|
-
object
|
|
40
|
+
def uri(keys, required: false)
|
|
41
|
+
object(keys, required: required) do |value|
|
|
41
42
|
case value
|
|
42
43
|
when ::String
|
|
43
|
-
raise
|
|
44
|
+
raise(AttributeError, "The #{keys.first} field cannot be empty") if value.empty?
|
|
44
45
|
begin
|
|
45
46
|
[Utils.deep_freeze(::URI.parse(value)), value.freeze]
|
|
46
47
|
rescue ::URI::InvalidURIError => e
|
|
47
|
-
raise
|
|
48
|
+
raise(AttributeError, "Illegal format for #{keys.first}: #{e.message}")
|
|
48
49
|
end
|
|
49
50
|
when ::URI::Generic
|
|
50
51
|
[Utils.deep_freeze(value), value.to_s.freeze]
|
|
51
52
|
else
|
|
52
|
-
raise
|
|
53
|
-
"
|
|
53
|
+
raise(AttributeError, "Illegal type for #{keys.first}: " \
|
|
54
|
+
"String or URI expected but #{value.class} found")
|
|
54
55
|
end
|
|
55
56
|
end
|
|
56
57
|
end
|
|
57
58
|
|
|
58
|
-
def rfc3339_date_time
|
|
59
|
-
object
|
|
59
|
+
def rfc3339_date_time(keys, required: false)
|
|
60
|
+
object(keys, required: required) do |value|
|
|
60
61
|
case value
|
|
61
62
|
when ::String
|
|
62
63
|
begin
|
|
63
64
|
[Utils.deep_freeze(::DateTime.rfc3339(value)), value.freeze]
|
|
64
65
|
rescue ::Date::Error => e
|
|
65
|
-
raise
|
|
66
|
+
raise(AttributeError, "Illegal format for #{keys.first}: #{e.message}")
|
|
66
67
|
end
|
|
67
68
|
when ::DateTime
|
|
68
69
|
[Utils.deep_freeze(value), value.rfc3339.freeze]
|
|
@@ -70,44 +71,44 @@ module CloudEvents
|
|
|
70
71
|
value = value.to_datetime
|
|
71
72
|
[Utils.deep_freeze(value), value.rfc3339.freeze]
|
|
72
73
|
else
|
|
73
|
-
raise
|
|
74
|
-
"
|
|
74
|
+
raise(AttributeError, "Illegal type for #{keys.first}: " \
|
|
75
|
+
"String, Time, or DateTime expected but #{value.class} found")
|
|
75
76
|
end
|
|
76
77
|
end
|
|
77
78
|
end
|
|
78
79
|
|
|
79
|
-
def content_type
|
|
80
|
-
object
|
|
80
|
+
def content_type(keys, required: false)
|
|
81
|
+
object(keys, required: required) do |value|
|
|
81
82
|
case value
|
|
82
83
|
when ::String
|
|
83
|
-
raise
|
|
84
|
+
raise(AttributeError, "The #{keys.first} field cannot be empty") if value.empty?
|
|
84
85
|
[ContentType.new(value), value.freeze]
|
|
85
86
|
when ContentType
|
|
86
87
|
[value, value.to_s]
|
|
87
88
|
else
|
|
88
|
-
raise
|
|
89
|
-
"
|
|
89
|
+
raise(AttributeError, "Illegal type for #{keys.first}: " \
|
|
90
|
+
"String, or ContentType expected but #{value.class} found")
|
|
90
91
|
end
|
|
91
92
|
end
|
|
92
93
|
end
|
|
93
94
|
|
|
94
|
-
def spec_version
|
|
95
|
-
object
|
|
95
|
+
def spec_version(keys, accept:)
|
|
96
|
+
object(keys, required: true) do |value|
|
|
96
97
|
case value
|
|
97
98
|
when ::String
|
|
98
|
-
raise
|
|
99
|
+
raise(SpecVersionError, "Unrecognized specversion: #{value}") unless accept =~ value
|
|
99
100
|
value.freeze
|
|
100
101
|
[value, value]
|
|
101
102
|
else
|
|
102
|
-
raise
|
|
103
|
-
"
|
|
103
|
+
raise(AttributeError, "Illegal type for #{keys.first}: " \
|
|
104
|
+
"String expected but #{value.class} found")
|
|
104
105
|
end
|
|
105
106
|
end
|
|
106
107
|
end
|
|
107
108
|
|
|
108
|
-
def data_object
|
|
109
|
-
object
|
|
110
|
-
Utils.deep_freeze
|
|
109
|
+
def data_object(keys, required: false)
|
|
110
|
+
object(keys, required: required, allow_nil: true) do |value|
|
|
111
|
+
Utils.deep_freeze(value)
|
|
111
112
|
[value, value]
|
|
112
113
|
end
|
|
113
114
|
end
|
|
@@ -116,21 +117,28 @@ module CloudEvents
|
|
|
116
117
|
|
|
117
118
|
private
|
|
118
119
|
|
|
119
|
-
def object
|
|
120
|
+
def object(keys, required: false, allow_nil: false)
|
|
120
121
|
value = UNDEFINED
|
|
121
122
|
keys.each do |key|
|
|
122
|
-
key_present = @args.key?
|
|
123
|
-
val = @args.delete
|
|
124
|
-
value = val if allow_nil && key_present || !allow_nil && !val.nil?
|
|
123
|
+
key_present = @args.key?(key)
|
|
124
|
+
val = @args.delete(key)
|
|
125
|
+
value = val if (allow_nil && key_present) || (!allow_nil && !val.nil?)
|
|
125
126
|
end
|
|
126
127
|
if value == UNDEFINED
|
|
127
|
-
raise
|
|
128
|
+
raise(AttributeError, "The #{keys.first} field is required") if required
|
|
128
129
|
return allow_nil ? UNDEFINED : nil
|
|
129
130
|
end
|
|
130
|
-
converted, raw = yield
|
|
131
|
+
converted, raw = yield(value)
|
|
131
132
|
@attributes[keys.first.freeze] = raw
|
|
132
133
|
converted
|
|
133
134
|
end
|
|
135
|
+
|
|
136
|
+
def check_attribute_name(key, requires_lc_start)
|
|
137
|
+
regex = requires_lc_start ? /^[a-z][a-z0-9]*$/ : /^[a-z0-9]+$/
|
|
138
|
+
unless regex.match?(key)
|
|
139
|
+
raise(AttributeError, "Illegal key: #{key.inspect} must consist only of digits and lower-case letters")
|
|
140
|
+
end
|
|
141
|
+
end
|
|
134
142
|
end
|
|
135
143
|
end
|
|
136
144
|
end
|
|
@@ -24,7 +24,7 @@ module CloudEvents
|
|
|
24
24
|
# or not provided, the value will be inferred from the content type
|
|
25
25
|
# if possible, or otherwise set to `nil` indicating not known.
|
|
26
26
|
#
|
|
27
|
-
def initialize
|
|
27
|
+
def initialize(content, content_type, batch: nil)
|
|
28
28
|
@content = content.freeze
|
|
29
29
|
@content_type = content_type
|
|
30
30
|
if batch.nil? && content_type&.media_type == "application"
|
|
@@ -63,7 +63,7 @@ module CloudEvents
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
## @private
|
|
66
|
-
def ==
|
|
66
|
+
def ==(other)
|
|
67
67
|
Opaque === other &&
|
|
68
68
|
@content == other.content &&
|
|
69
69
|
@content_type == other.content_type &&
|
|
@@ -73,7 +73,7 @@ module CloudEvents
|
|
|
73
73
|
|
|
74
74
|
## @private
|
|
75
75
|
def hash
|
|
76
|
-
@content
|
|
76
|
+
[@content, @content_type, @batch].hash
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
end
|
|
@@ -8,37 +8,37 @@ module CloudEvents
|
|
|
8
8
|
#
|
|
9
9
|
module Utils
|
|
10
10
|
class << self
|
|
11
|
-
def deep_freeze
|
|
11
|
+
def deep_freeze(obj)
|
|
12
12
|
case obj
|
|
13
13
|
when ::Hash
|
|
14
14
|
obj.each do |key, val|
|
|
15
|
-
deep_freeze
|
|
16
|
-
deep_freeze
|
|
15
|
+
deep_freeze(key)
|
|
16
|
+
deep_freeze(val)
|
|
17
17
|
end
|
|
18
18
|
when ::Array
|
|
19
19
|
obj.each do |val|
|
|
20
|
-
deep_freeze
|
|
20
|
+
deep_freeze(val)
|
|
21
21
|
end
|
|
22
22
|
else
|
|
23
23
|
obj.instance_variables.each do |iv|
|
|
24
|
-
deep_freeze
|
|
24
|
+
deep_freeze(obj.instance_variable_get(iv))
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
obj.freeze
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def deep_dup
|
|
30
|
+
def deep_dup(obj)
|
|
31
31
|
case obj
|
|
32
32
|
when ::Hash
|
|
33
|
-
obj.each_with_object({}) { |(key, val), hash| hash[deep_dup
|
|
33
|
+
obj.each_with_object({}) { |(key, val), hash| hash[deep_dup(key)] = deep_dup(val) }
|
|
34
34
|
when ::Array
|
|
35
|
-
obj.map { |val| deep_dup
|
|
35
|
+
obj.map { |val| deep_dup(val) }
|
|
36
36
|
else
|
|
37
37
|
obj.dup
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
def keys_to_strings
|
|
41
|
+
def keys_to_strings(hash)
|
|
42
42
|
result = {}
|
|
43
43
|
hash.each do |key, val|
|
|
44
44
|
result[key.to_s] = val
|
|
@@ -75,20 +75,20 @@ module CloudEvents
|
|
|
75
75
|
# (Also available using the deprecated keyword `attributes`.)
|
|
76
76
|
# @param args [keywords] The data and attributes, as keyword arguments.
|
|
77
77
|
#
|
|
78
|
-
def initialize
|
|
79
|
-
interpreter = FieldInterpreter.new
|
|
80
|
-
@spec_version = interpreter.spec_version
|
|
81
|
-
@id = interpreter.string
|
|
82
|
-
@source = interpreter.uri
|
|
83
|
-
@type = interpreter.string
|
|
84
|
-
@data = interpreter.data_object
|
|
78
|
+
def initialize(set_attributes: nil, attributes: nil, **args)
|
|
79
|
+
interpreter = FieldInterpreter.new(set_attributes || attributes || args)
|
|
80
|
+
@spec_version = interpreter.spec_version(["specversion", "spec_version"], accept: /^0\.3$/)
|
|
81
|
+
@id = interpreter.string(["id"], required: true)
|
|
82
|
+
@source = interpreter.uri(["source"], required: true)
|
|
83
|
+
@type = interpreter.string(["type"], required: true)
|
|
84
|
+
@data = interpreter.data_object(["data"])
|
|
85
85
|
@data = nil if @data == FieldInterpreter::UNDEFINED
|
|
86
|
-
@data_content_encoding = interpreter.string
|
|
87
|
-
@data_content_type = interpreter.content_type
|
|
88
|
-
@schema_url = interpreter.uri
|
|
89
|
-
@subject = interpreter.string
|
|
90
|
-
@time = interpreter.rfc3339_date_time
|
|
91
|
-
@attributes = interpreter.finish_attributes
|
|
86
|
+
@data_content_encoding = interpreter.string(["datacontentencoding", "data_content_encoding"])
|
|
87
|
+
@data_content_type = interpreter.content_type(["datacontenttype", "data_content_type"])
|
|
88
|
+
@schema_url = interpreter.uri(["schemaurl", "schema_url"])
|
|
89
|
+
@subject = interpreter.string(["subject"])
|
|
90
|
+
@time = interpreter.rfc3339_date_time(["time"])
|
|
91
|
+
@attributes = interpreter.finish_attributes(requires_lc_start: true)
|
|
92
92
|
freeze
|
|
93
93
|
end
|
|
94
94
|
|
|
@@ -101,9 +101,9 @@ module CloudEvents
|
|
|
101
101
|
# @param changes [keywords] See {#initialize} for a list of arguments.
|
|
102
102
|
# @return [FunctionFramework::CloudEvents::Event]
|
|
103
103
|
#
|
|
104
|
-
def with
|
|
105
|
-
attributes = @attributes.merge
|
|
106
|
-
V0.new
|
|
104
|
+
def with(**changes)
|
|
105
|
+
attributes = @attributes.merge(changes)
|
|
106
|
+
V0.new(set_attributes: attributes)
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
##
|
|
@@ -125,7 +125,7 @@ module CloudEvents
|
|
|
125
125
|
# @param key [String,Symbol] The attribute name.
|
|
126
126
|
# @return [String,nil]
|
|
127
127
|
#
|
|
128
|
-
def []
|
|
128
|
+
def [](key)
|
|
129
129
|
@attributes[key.to_s]
|
|
130
130
|
end
|
|
131
131
|
|
|
@@ -136,7 +136,7 @@ module CloudEvents
|
|
|
136
136
|
# @return [Hash]
|
|
137
137
|
#
|
|
138
138
|
def to_h
|
|
139
|
-
Utils.deep_dup
|
|
139
|
+
Utils.deep_dup(@attributes)
|
|
140
140
|
end
|
|
141
141
|
|
|
142
142
|
##
|
|
@@ -225,7 +225,7 @@ module CloudEvents
|
|
|
225
225
|
attr_reader :time
|
|
226
226
|
|
|
227
227
|
## @private
|
|
228
|
-
def ==
|
|
228
|
+
def ==(other)
|
|
229
229
|
other.is_a?(V0) && @attributes == other.instance_variable_get(:@attributes)
|
|
230
230
|
end
|
|
231
231
|
alias eql? ==
|
|
@@ -136,24 +136,24 @@ module CloudEvents
|
|
|
136
136
|
# (Also available using the deprecated keyword `attributes`.)
|
|
137
137
|
# @param args [keywords] The data and attributes, as keyword arguments.
|
|
138
138
|
#
|
|
139
|
-
def initialize
|
|
140
|
-
interpreter = FieldInterpreter.new
|
|
141
|
-
@spec_version = interpreter.spec_version
|
|
142
|
-
@id = interpreter.string
|
|
143
|
-
@source = interpreter.uri
|
|
144
|
-
@type = interpreter.string
|
|
145
|
-
@data_encoded = interpreter.string
|
|
146
|
-
@data = interpreter.data_object
|
|
139
|
+
def initialize(set_attributes: nil, attributes: nil, **args)
|
|
140
|
+
interpreter = FieldInterpreter.new(set_attributes || attributes || args)
|
|
141
|
+
@spec_version = interpreter.spec_version(["specversion", "spec_version"], accept: /^1(\.|$)/)
|
|
142
|
+
@id = interpreter.string(["id"], required: true)
|
|
143
|
+
@source = interpreter.uri(["source"], required: true)
|
|
144
|
+
@type = interpreter.string(["type"], required: true)
|
|
145
|
+
@data_encoded = interpreter.string(["data_encoded"], allow_empty: true)
|
|
146
|
+
@data = interpreter.data_object(["data"])
|
|
147
147
|
if @data == FieldInterpreter::UNDEFINED
|
|
148
148
|
@data = @data_encoded
|
|
149
149
|
@data_decoded = false
|
|
150
150
|
else
|
|
151
151
|
@data_decoded = true
|
|
152
152
|
end
|
|
153
|
-
@data_content_type = interpreter.content_type
|
|
154
|
-
@data_schema = interpreter.uri
|
|
155
|
-
@subject = interpreter.string
|
|
156
|
-
@time = interpreter.rfc3339_date_time
|
|
153
|
+
@data_content_type = interpreter.content_type(["datacontenttype", "data_content_type"])
|
|
154
|
+
@data_schema = interpreter.uri(["dataschema", "data_schema"])
|
|
155
|
+
@subject = interpreter.string(["subject"])
|
|
156
|
+
@time = interpreter.rfc3339_date_time(["time"])
|
|
157
157
|
@attributes = interpreter.finish_attributes
|
|
158
158
|
freeze
|
|
159
159
|
end
|
|
@@ -167,15 +167,15 @@ module CloudEvents
|
|
|
167
167
|
# @param changes [keywords] See {#initialize} for a list of arguments.
|
|
168
168
|
# @return [FunctionFramework::CloudEvents::Event]
|
|
169
169
|
#
|
|
170
|
-
def with
|
|
171
|
-
changes = Utils.keys_to_strings
|
|
170
|
+
def with(**changes)
|
|
171
|
+
changes = Utils.keys_to_strings(changes)
|
|
172
172
|
attributes = @attributes.dup
|
|
173
173
|
if changes.key?("data") || changes.key?("data_encoded")
|
|
174
|
-
attributes.delete
|
|
175
|
-
attributes.delete
|
|
174
|
+
attributes.delete("data")
|
|
175
|
+
attributes.delete("data_encoded")
|
|
176
176
|
end
|
|
177
|
-
attributes.merge!
|
|
178
|
-
V1.new
|
|
177
|
+
attributes.merge!(changes)
|
|
178
|
+
V1.new(set_attributes: attributes)
|
|
179
179
|
end
|
|
180
180
|
|
|
181
181
|
##
|
|
@@ -197,7 +197,7 @@ module CloudEvents
|
|
|
197
197
|
# @param key [String,Symbol] The attribute name.
|
|
198
198
|
# @return [String,nil]
|
|
199
199
|
#
|
|
200
|
-
def []
|
|
200
|
+
def [](key)
|
|
201
201
|
@attributes[key.to_s]
|
|
202
202
|
end
|
|
203
203
|
|
|
@@ -208,7 +208,7 @@ module CloudEvents
|
|
|
208
208
|
# @return [Hash]
|
|
209
209
|
#
|
|
210
210
|
def to_h
|
|
211
|
-
Utils.deep_dup
|
|
211
|
+
Utils.deep_dup(@attributes)
|
|
212
212
|
end
|
|
213
213
|
|
|
214
214
|
##
|
|
@@ -330,7 +330,7 @@ module CloudEvents
|
|
|
330
330
|
attr_reader :time
|
|
331
331
|
|
|
332
332
|
## @private
|
|
333
|
-
def ==
|
|
333
|
+
def ==(other)
|
|
334
334
|
other.is_a?(V1) && @attributes == other.instance_variable_get(:@attributes)
|
|
335
335
|
end
|
|
336
336
|
alias eql? ==
|
data/lib/cloud_events/event.rb
CHANGED
|
@@ -58,14 +58,14 @@ module CloudEvents
|
|
|
58
58
|
# @param spec_version [String] The required `specversion` field.
|
|
59
59
|
# @param kwargs [keywords] Additional parameters for the event.
|
|
60
60
|
#
|
|
61
|
-
def create
|
|
61
|
+
def create(spec_version:, **kwargs)
|
|
62
62
|
case spec_version
|
|
63
63
|
when "0.3"
|
|
64
|
-
V0.new
|
|
64
|
+
V0.new(spec_version: spec_version, **kwargs)
|
|
65
65
|
when /^1(\.|$)/
|
|
66
|
-
V1.new
|
|
66
|
+
V1.new(spec_version: spec_version, **kwargs)
|
|
67
67
|
else
|
|
68
|
-
raise
|
|
68
|
+
raise(SpecVersionError, "Unrecognized specversion: #{spec_version}")
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
71
|
alias new create
|