cloud_events 0.3.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -0
- data/README.md +12 -10
- data/lib/cloud_events/content_type.rb +6 -4
- data/lib/cloud_events/errors.rb +37 -5
- data/lib/cloud_events/event/field_interpreter.rb +3 -3
- data/lib/cloud_events/event/opaque.rb +80 -0
- data/lib/cloud_events/event/v0.rb +10 -5
- data/lib/cloud_events/event/v1.rb +144 -21
- data/lib/cloud_events/event.rb +1 -1
- data/lib/cloud_events/format.rb +277 -0
- data/lib/cloud_events/http_binding.rb +335 -150
- data/lib/cloud_events/json_format.rb +232 -61
- data/lib/cloud_events/text_format.rb +73 -0
- data/lib/cloud_events/version.rb +1 -1
- data/lib/cloud_events.rb +2 -0
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 036b0516dd1cbb3d6f2c4855809facc6edb4ac994b00355056182a704a072306
|
4
|
+
data.tar.gz: 4eccf559900a089b4a86ce269a30bd604dd4bcad3973ad5ffbe69735acb2a7e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0d255359ad545ec1f0898f437b2b220e72cc8766de1f59e0534c71c4863fd093b410e9350048506d8b99a22235d23aef9b9c4ca0fee757242229cdd283faaf2
|
7
|
+
data.tar.gz: 84a043396ad6cd11e6cd05fd7ce6bdd2993fcede29d2fc780c88419dc2bbd99d230c573b8c237f53940e033fe42449c0976e85c9842fef6dd829e798ecd4daa2
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,48 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
### v0.7.0 / 2022-01-14
|
4
|
+
|
5
|
+
* HttpBinding#probable_event? returns false if the request method is GET or HEAD.
|
6
|
+
* HttpBinding#decode_event raises NotCloudEventError if the request method is GET or HEAD.
|
7
|
+
* Fixed a NoMethodError if nil content was passed to the ContentType constructor.
|
8
|
+
|
9
|
+
### v0.6.0 / 2021-08-23
|
10
|
+
|
11
|
+
This update further clarifies and cleans up the encoding behavior of event payloads. In particular, the event object now includes explicitly encoded data in the new `data_encoded` field, and provides information on whether the existing `data` field contains an encoded or decoded form of the payload.
|
12
|
+
|
13
|
+
* Added `data_encoded`, `data_decoded?` and `data?` methods to `CloudEvents::Event::V1`, added `:data_encoded` as an input attribute, and clarified the encoding semantics of each field.
|
14
|
+
* Changed `:attributes` keyword argument in event constructors to `:set_attributes`, to avoid any possible collision with a real extension attribute name. (The old argument name is deprecated and will be removed in 1.0.)
|
15
|
+
* Fixed various inconsistencies in the data encoding behavior of `JsonFormat` and `HttpBinding`.
|
16
|
+
* Support passing a data content encoder/decoder into `JsonFormat#encode_event` and `JsonFormat#decode_event`.
|
17
|
+
* Provided `TextFormat` to handle media types with trivial encoding.
|
18
|
+
* Provided `Format::Multi` to handle checking a series of encoders/decoders.
|
19
|
+
|
20
|
+
### v0.5.1 / 2021-06-28
|
21
|
+
|
22
|
+
* ADDED: Add HttpBinding#probable_event?
|
23
|
+
* FIXED: Fixed a NoMethodError when a format declined to decode an http request
|
24
|
+
|
25
|
+
### v0.5.0 / 2021-06-28
|
26
|
+
|
27
|
+
This is a significant update that provides several important spec-related and usability fixes. Some of the behavioral changes are breaking, so to preserve compatibility, new methods were added and old methods deprecated, particularly in the HttpBinding class. Additionally, the formatter interface has been simplified and expanded to support payload formatting.
|
28
|
+
|
29
|
+
* CHANGED: Deprecated HttpBinding#decode_rack_env and replaced with HttpBinding#decode_event. (The old method remains for backward compatibility, but will be removed in version 1.0). The new decode_event method has the following differences:
|
30
|
+
* decode_event raises NotCloudEventError (rather than returning nil) if given an HTTP request that does not seem to have been intended as a CloudEvent.
|
31
|
+
* decode_event takes an allow_opaque argument that, when set to true, returns a CloudEvents::Event::Opaque (rather than raising an exception) if given a structured event with a format not known by the SDK. Opaque event objects cannot have their fields inspected, but can be reserialized for retransmission to another event handler.
|
32
|
+
* decode_event in binary content mode now parses JSON content-types and exposes the data attribute as a JSON value.
|
33
|
+
* CHANGED: Deprecated the HttpBinding encoding entrypoints (encode_structured_content, encode_batched_content, and encode_binary_content) and replaced with a single encode_event entrypoint that handles all cases via the structured_format argument. (The old methods remain for backward compatibility, but will be removed in version 1.0). In addition, the new encode_event method has the following differences:
|
34
|
+
* encode_event in binary content mode now interprets a string-valued data attribute as a JSON string and serializes it (i.e. wraps it in quotes) if the data_content_type has a JSON format. This is for compatibility with the behavior of the JSON structured mode which always treats the data attribute as a JSON value if the data_content_type indicates JSON.
|
35
|
+
* CHANGED: The JsonFormat class interface was reworked to be more generic, combine the structured and batched calls, and add calls to handle data payloads. A Format module has been added to specify the interface used by JsonFormat and future formatters. (Breaking change of internal interfaces)
|
36
|
+
* CHANGED: Renamed HttpContentError to UnsupportedFormatError to better reflect the specific issue being reported, and to eliminate the coupling to http. The old name remains aliased to the new name, but is deprecated and will be removed in version 1.0.
|
37
|
+
* CHANGED: If format-driven parsing (e.g. parsing a JSON document) fails, a FormatSyntaxError will be raised instead of, for example, a JSON-specific error. The lower-level parser error can still be accessed from the exception's "cause".
|
38
|
+
* FIXED: JsonFormat now sets the datacontenttype attribute explicitly to "application/json" if it isn't otherwise set.
|
39
|
+
|
40
|
+
### v0.4.0 / 2021-05-26
|
41
|
+
|
42
|
+
* ADDED: ContentType can take an optional default charset
|
43
|
+
* FIXED: Binary HTTP format parses quoted tokens according to RFC 7230 section 3.2.6
|
44
|
+
* FIXED: When encoding structured events for HTTP transport, the content-type now includes the charset
|
45
|
+
|
3
46
|
### v0.3.1 / 2021-04-25
|
4
47
|
|
5
48
|
* FIXED: Fixed exception when decoding from a rack source that uses InputWrapper
|
data/README.md
CHANGED
@@ -13,7 +13,7 @@ Features:
|
|
13
13
|
JSON Batch Format.
|
14
14
|
* Support for sending and receiving CloudEvents via HTTP Bindings.
|
15
15
|
* Supports the [CloudEvent 0.3](https://github.com/cloudevents/spec/tree/v0.3)
|
16
|
-
and [CloudEvents 1.0](https://github.com/cloudevents/spec/tree/v1.0)
|
16
|
+
and [CloudEvents 1.0](https://github.com/cloudevents/spec/tree/v1.0.1)
|
17
17
|
specifications.
|
18
18
|
* Extensible to additional formats and protocol bindings, and future
|
19
19
|
specification versions.
|
@@ -35,7 +35,7 @@ A simple [Sinatra](https://sinatrarb.com) app that receives CloudEvents:
|
|
35
35
|
```ruby
|
36
36
|
# examples/server/Gemfile
|
37
37
|
source "https://rubygems.org"
|
38
|
-
gem "cloud_events", "~> 0.
|
38
|
+
gem "cloud_events", "~> 0.6"
|
39
39
|
gem "sinatra", "~> 2.0"
|
40
40
|
```
|
41
41
|
|
@@ -47,7 +47,7 @@ require "cloud_events"
|
|
47
47
|
cloud_events_http = CloudEvents::HttpBinding.default
|
48
48
|
|
49
49
|
post "/" do
|
50
|
-
event = cloud_events_http.
|
50
|
+
event = cloud_events_http.decode_event request.env
|
51
51
|
logger.info "Received CloudEvent: #{event.to_h}"
|
52
52
|
end
|
53
53
|
```
|
@@ -59,7 +59,7 @@ A simple Ruby script that sends a CloudEvent:
|
|
59
59
|
```ruby
|
60
60
|
# examples/client/Gemfile
|
61
61
|
source "https://rubygems.org"
|
62
|
-
gem "cloud_events", "~> 0.
|
62
|
+
gem "cloud_events", "~> 0.6"
|
63
63
|
```
|
64
64
|
|
65
65
|
```ruby
|
@@ -69,14 +69,16 @@ require "net/http"
|
|
69
69
|
require "uri"
|
70
70
|
|
71
71
|
data = { message: "Hello, CloudEvents!" }
|
72
|
-
event = CloudEvents::Event.create
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
72
|
+
event = CloudEvents::Event.create \
|
73
|
+
spec_version: "1.0",
|
74
|
+
id: "1234-1234-1234",
|
75
|
+
source: "/mycontext",
|
76
|
+
type: "com.example.someevent",
|
77
|
+
data_content_type: "application/json",
|
78
|
+
data: data
|
77
79
|
|
78
80
|
cloud_events_http = CloudEvents::HttpBinding.default
|
79
|
-
headers, body = cloud_events_http.
|
81
|
+
headers, body = cloud_events_http.encode_event event
|
80
82
|
Net::HTTP.post URI("http://localhost:4567"), body, headers
|
81
83
|
```
|
82
84
|
|
@@ -21,16 +21,18 @@ module CloudEvents
|
|
21
21
|
# Parse the given header value.
|
22
22
|
#
|
23
23
|
# @param string [String] Content-Type header value in RFC 2045 format
|
24
|
+
# @param default_charset [String] Optional. The charset to use if none is
|
25
|
+
# specified. Defaults to `us-ascii`.
|
24
26
|
#
|
25
|
-
def initialize string
|
26
|
-
@string = string
|
27
|
+
def initialize string, default_charset: nil
|
28
|
+
@string = string.to_s
|
27
29
|
@media_type = "text"
|
28
30
|
@subtype_base = @subtype = "plain"
|
29
31
|
@subtype_format = nil
|
30
32
|
@params = []
|
31
|
-
@charset = "us-ascii"
|
33
|
+
@charset = default_charset || "us-ascii"
|
32
34
|
@error_message = nil
|
33
|
-
parse consume_comments string.strip
|
35
|
+
parse consume_comments @string.strip
|
34
36
|
@canonical_string = "#{@media_type}/#{@subtype}" +
|
35
37
|
@params.map { |k, v| "; #{k}=#{maybe_quote v}" }.join
|
36
38
|
full_freeze
|
data/lib/cloud_events/errors.rb
CHANGED
@@ -8,21 +8,53 @@ module CloudEvents
|
|
8
8
|
end
|
9
9
|
|
10
10
|
##
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# An error raised when a protocol binding was asked to decode a CloudEvent
|
12
|
+
# from input data, but does not believe that the data was intended to be a
|
13
|
+
# CloudEvent. For example, the HttpBinding might raise this exception if
|
14
|
+
# given a request that has neither the requisite headers for binary content
|
15
|
+
# mode, nor an appropriate content-type for structured content mode.
|
13
16
|
#
|
14
|
-
class
|
17
|
+
class NotCloudEventError < CloudEventsError
|
15
18
|
end
|
16
19
|
|
17
20
|
##
|
18
|
-
#
|
21
|
+
# An error raised when a protocol binding was asked to decode a CloudEvent
|
22
|
+
# from input data, and the data appears to be a CloudEvent, but was encoded
|
23
|
+
# in a format that is not supported. Some protocol bindings can be configured
|
24
|
+
# to return a {CloudEvents::Event::Opaque} object instead of raising this
|
25
|
+
# error.
|
26
|
+
#
|
27
|
+
class UnsupportedFormatError < CloudEventsError
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# An error raised when a protocol binding was asked to decode a CloudEvent
|
32
|
+
# from input data, and the data appears to be intended as a CloudEvent, but
|
33
|
+
# has unrecoverable format or syntax errors. This error _may_ have a `cause`
|
34
|
+
# such as a `JSON::ParserError` with additional information.
|
35
|
+
#
|
36
|
+
class FormatSyntaxError < CloudEventsError
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# An error raised when a `specversion` is set to a value not recognized or
|
41
|
+
# supported by the SDK.
|
19
42
|
#
|
20
43
|
class SpecVersionError < CloudEventsError
|
21
44
|
end
|
22
45
|
|
23
46
|
##
|
24
|
-
#
|
47
|
+
# An error raised when a malformed CloudEvents attribute is encountered,
|
48
|
+
# often because a required attribute is missing, or a value does not match
|
49
|
+
# the attribute's type specification.
|
25
50
|
#
|
26
51
|
class AttributeError < CloudEventsError
|
27
52
|
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Alias of UnsupportedFormatError, for backward compatibility.
|
56
|
+
#
|
57
|
+
# @deprecated Will be removed in version 1.0. Use {UnsupportedFormatError}.
|
58
|
+
#
|
59
|
+
HttpContentError = UnsupportedFormatError
|
28
60
|
end
|
@@ -22,11 +22,11 @@ module CloudEvents
|
|
22
22
|
@attributes.freeze
|
23
23
|
end
|
24
24
|
|
25
|
-
def string keys, required: false
|
25
|
+
def string keys, required: false, allow_empty: false
|
26
26
|
object keys, required: required do |value|
|
27
27
|
case value
|
28
28
|
when ::String
|
29
|
-
raise AttributeError, "The #{keys.first} field cannot be empty" if value.empty?
|
29
|
+
raise AttributeError, "The #{keys.first} field cannot be empty" if value.empty? && !allow_empty
|
30
30
|
value.freeze
|
31
31
|
[value, value]
|
32
32
|
else
|
@@ -125,7 +125,7 @@ module CloudEvents
|
|
125
125
|
end
|
126
126
|
if value == UNDEFINED
|
127
127
|
raise AttributeError, "The #{keys.first} field is required" if required
|
128
|
-
return nil
|
128
|
+
return allow_nil ? UNDEFINED : nil
|
129
129
|
end
|
130
130
|
converted, raw = yield value
|
131
131
|
@attributes[keys.first.freeze] = raw
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CloudEvents
|
4
|
+
module Event
|
5
|
+
##
|
6
|
+
# This object represents opaque event data that arrived in structured
|
7
|
+
# content mode but was not in a recognized format. It may represent a
|
8
|
+
# single event or a batch of events.
|
9
|
+
#
|
10
|
+
# The event data is retained in a form that can be reserialized (in a
|
11
|
+
# structured cotent mode in the same format) but cannot otherwise be
|
12
|
+
# inspected.
|
13
|
+
#
|
14
|
+
# This object is immutable, and Ractor-shareable on Ruby 3.
|
15
|
+
#
|
16
|
+
class Opaque
|
17
|
+
##
|
18
|
+
# Create an opaque object wrapping the given content and a content type.
|
19
|
+
#
|
20
|
+
# @param content [String] The opaque serialized event data.
|
21
|
+
# @param content_type [CloudEvents::ContentType,nil] The content type,
|
22
|
+
# or `nil` if there is no content type.
|
23
|
+
# @param batch [boolean] Whether this represents a batch. If set to `nil`
|
24
|
+
# or not provided, the value will be inferred from the content type
|
25
|
+
# if possible, or otherwise set to `nil` indicating not known.
|
26
|
+
#
|
27
|
+
def initialize content, content_type, batch: nil
|
28
|
+
@content = content.freeze
|
29
|
+
@content_type = content_type
|
30
|
+
if batch.nil? && content_type&.media_type == "application"
|
31
|
+
case content_type.subtype_base
|
32
|
+
when "cloudevents"
|
33
|
+
batch = false
|
34
|
+
when "cloudevents-batch"
|
35
|
+
batch = true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
@batch = batch
|
39
|
+
freeze
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# The opaque serialized event data
|
44
|
+
#
|
45
|
+
# @return [String]
|
46
|
+
#
|
47
|
+
attr_reader :content
|
48
|
+
|
49
|
+
##
|
50
|
+
# The content type, or `nil` if there is no content type.
|
51
|
+
#
|
52
|
+
# @return [CloudEvents::ContentType,nil]
|
53
|
+
#
|
54
|
+
attr_reader :content_type
|
55
|
+
|
56
|
+
##
|
57
|
+
# Whether this represents a batch, or `nil` if not known.
|
58
|
+
#
|
59
|
+
# @return [boolean,nil]
|
60
|
+
#
|
61
|
+
def batch?
|
62
|
+
@batch
|
63
|
+
end
|
64
|
+
|
65
|
+
## @private
|
66
|
+
def == other
|
67
|
+
Opaque === other &&
|
68
|
+
@content == other.content &&
|
69
|
+
@content_type == other.content_type &&
|
70
|
+
@batch == other.batch?
|
71
|
+
end
|
72
|
+
alias eql? ==
|
73
|
+
|
74
|
+
## @private
|
75
|
+
def hash
|
76
|
+
@content.hash ^ @content_type.hash ^ @batch.hash
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -34,7 +34,10 @@ module CloudEvents
|
|
34
34
|
# Create a new cloud event object with the given data and attributes.
|
35
35
|
#
|
36
36
|
# Event attributes may be presented as keyword arguments, or as a Hash
|
37
|
-
# passed in via the `
|
37
|
+
# passed in via the special `:set_attributes` keyword argument (but not
|
38
|
+
# both). The `:set_attributes` keyword argument is useful for passing in
|
39
|
+
# attributes whose keys are strings rather than symbols, which some
|
40
|
+
# versions of Ruby will not accept as keyword arguments.
|
38
41
|
#
|
39
42
|
# The following standard attributes are supported and exposed as
|
40
43
|
# attribute methods on the object.
|
@@ -68,16 +71,18 @@ module CloudEvents
|
|
68
71
|
# `:data` field, for example if you pass a structured hash. If this is an
|
69
72
|
# issue, make a deep copy of objects before passing to this constructor.
|
70
73
|
#
|
71
|
-
# @param
|
74
|
+
# @param set_attributes [Hash] The data and attributes, as a hash.
|
75
|
+
# (Also available using the deprecated keyword `attributes`.)
|
72
76
|
# @param args [keywords] The data and attributes, as keyword arguments.
|
73
77
|
#
|
74
|
-
def initialize attributes: nil, **args
|
75
|
-
interpreter = FieldInterpreter.new attributes || args
|
78
|
+
def initialize set_attributes: nil, attributes: nil, **args
|
79
|
+
interpreter = FieldInterpreter.new set_attributes || attributes || args
|
76
80
|
@spec_version = interpreter.spec_version ["specversion", "spec_version"], accept: /^0\.3$/
|
77
81
|
@id = interpreter.string ["id"], required: true
|
78
82
|
@source = interpreter.uri ["source"], required: true
|
79
83
|
@type = interpreter.string ["type"], required: true
|
80
84
|
@data = interpreter.data_object ["data"]
|
85
|
+
@data = nil if @data == FieldInterpreter::UNDEFINED
|
81
86
|
@data_content_encoding = interpreter.string ["datacontentencoding", "data_content_encoding"]
|
82
87
|
@data_content_type = interpreter.content_type ["datacontenttype", "data_content_type"]
|
83
88
|
@schema_url = interpreter.uri ["schemaurl", "schema_url"]
|
@@ -98,7 +103,7 @@ module CloudEvents
|
|
98
103
|
#
|
99
104
|
def with **changes
|
100
105
|
attributes = @attributes.merge changes
|
101
|
-
V0.new
|
106
|
+
V0.new set_attributes: attributes
|
102
107
|
end
|
103
108
|
|
104
109
|
##
|
@@ -14,10 +14,29 @@ module CloudEvents
|
|
14
14
|
# This object represents a complete CloudEvent, including the event data
|
15
15
|
# and context attributes. It supports the standard required and optional
|
16
16
|
# attributes defined in CloudEvents V1.0, and arbitrary extension
|
17
|
-
# attributes.
|
17
|
+
# attributes.
|
18
|
+
#
|
19
|
+
# Values for most attributes can be obtained in their encoded string form
|
18
20
|
# via the {Event::V1#[]} method. Additionally, standard attributes have
|
19
|
-
# their own accessor methods that may return
|
20
|
-
# `DateTime` for the `time` attribute).
|
21
|
+
# their own accessor methods that may return decoded Ruby objects (such as
|
22
|
+
# a `DateTime` object for the `time` attribute).
|
23
|
+
#
|
24
|
+
# The `data` attribute is treated specially because it is subject to
|
25
|
+
# arbitrary encoding governed by the `datacontenttype` attribute. Data is
|
26
|
+
# expressed in two related fields: {Event::V1#data} and
|
27
|
+
# {Event::V1#data_encoded}. The former, `data`, _may_ be an arbitrary Ruby
|
28
|
+
# object representing the decoded form of the data (for example, a Hash for
|
29
|
+
# most JSON-formatted data.) The latter, `data_encoded`, _must_, if
|
30
|
+
# present, be a Ruby String object representing the encoded string or
|
31
|
+
# byte array form of the data.
|
32
|
+
#
|
33
|
+
# When the CloudEvents Ruby SDK encodes an event for transmission, it will
|
34
|
+
# use the `data_encoded` field if present. Otherwise, it will attempt to
|
35
|
+
# encode the `data` field using any available encoder that recognizes the
|
36
|
+
# content-type. Currently, text and JSON types are supported. If the type
|
37
|
+
# is not supported, event encoding may fail. It is thus recommended that
|
38
|
+
# applications provide a `data_encoded` string, if the `data` object is
|
39
|
+
# nontrivially encoded.
|
21
40
|
#
|
22
41
|
# This object is immutable, and Ractor-shareable on Ruby 3. The data and
|
23
42
|
# attribute values can be retrieved but not modified. To obtain an event
|
@@ -33,8 +52,13 @@ module CloudEvents
|
|
33
52
|
##
|
34
53
|
# Create a new cloud event object with the given data and attributes.
|
35
54
|
#
|
55
|
+
# ### Specifying event attributes
|
56
|
+
#
|
36
57
|
# Event attributes may be presented as keyword arguments, or as a Hash
|
37
|
-
# passed in via the `
|
58
|
+
# passed in via the special `:set_attributes` keyword argument (but not
|
59
|
+
# both). The `:set_attributes` keyword argument is useful for passing in
|
60
|
+
# attributes whose keys are strings rather than symbols, which some
|
61
|
+
# versions of Ruby will not accept as keyword arguments.
|
38
62
|
#
|
39
63
|
# The following standard attributes are supported and exposed as
|
40
64
|
# attribute methods on the object.
|
@@ -45,11 +69,15 @@ module CloudEvents
|
|
45
69
|
# * **:source** [`String`, `URI`] - _required_ - The event `source`
|
46
70
|
# field.
|
47
71
|
# * **:type** [`String`] - _required_ - The event `type` field.
|
48
|
-
# * **:data** [`Object`] - _optional_ - The
|
49
|
-
#
|
72
|
+
# * **:data** [`Object`] - _optional_ - The "decoded" Ruby object form
|
73
|
+
# of the event `data` field, if known. (e.g. a Hash representing a
|
74
|
+
# JSON document)
|
75
|
+
# * **:data_encoded** [`String`] - _optional_ - The "encoded" string
|
76
|
+
# form of the event `data` field, if known. This should be set along
|
77
|
+
# with the `data_content_type`.
|
50
78
|
# * **:data_content_type** (or **:datacontenttype**) [`String`,
|
51
|
-
# {ContentType}] - _optional_ - The content-type for the data
|
52
|
-
#
|
79
|
+
# {ContentType}] - _optional_ - The content-type for the encoded data
|
80
|
+
# (i.e. the event `datacontenttype` field.)
|
53
81
|
# * **:data_schema** (or **:dataschema**) [`String`, `URI`] -
|
54
82
|
# _optional_ - The event `dataschema` field.
|
55
83
|
# * **:subject** [`String`] - _optional_ - The event `subject` field.
|
@@ -65,16 +93,63 @@ module CloudEvents
|
|
65
93
|
# `:data` field, for example if you pass a structured hash. If this is an
|
66
94
|
# issue, make a deep copy of objects before passing to this constructor.
|
67
95
|
#
|
68
|
-
#
|
96
|
+
# ### Specifying payload data
|
97
|
+
#
|
98
|
+
# Typically you should provide _both_ the `:data` and `:data_encoded`
|
99
|
+
# fields, the former representing the decoded (Ruby object) form of the
|
100
|
+
# data, and the second providing a hint to formatters and protocol
|
101
|
+
# bindings for how to seralize the data. In this case, the {#data} and
|
102
|
+
# {#data_encoded} methods will return the corresponding values, and
|
103
|
+
# {#data_decoded?} will return true to indicate that {#data} represents
|
104
|
+
# the decoded form.
|
105
|
+
#
|
106
|
+
# If you provide _only_ the `:data` field, omitting `:data_encoded`, then
|
107
|
+
# the value is expected to represent the decoded (Ruby object) form of
|
108
|
+
# the data. The {#data} method will return this decoded value, and
|
109
|
+
# {#data_decoded?} will return true. The {#data_encoded} method will
|
110
|
+
# return nil.
|
111
|
+
# When serializing such an event, it will be up to the formatter or
|
112
|
+
# protocol binding to encode the data. This means serialization _could_
|
113
|
+
# fail if the formatter does not understand the data's content type.
|
114
|
+
# Omitting `:data_encoded` is common if the content type is JSON related
|
115
|
+
# (e.g. `application/json`) and the event is being encoded in JSON
|
116
|
+
# structured format, because the data encoding is trivial. This form can
|
117
|
+
# also be used when the content type is `text/*`, for which encoding is
|
118
|
+
# also trivial.
|
119
|
+
#
|
120
|
+
# If you provide _only_ the `:data_encoded` field, omitting `:data`, then
|
121
|
+
# the value is expected to represent the encoded (string) form of the
|
122
|
+
# data. The {#data_encoded} method will return this value. Additionally,
|
123
|
+
# the {#data} method will return the same _encoded_ value, and
|
124
|
+
# {#data_decoded?} will return false.
|
125
|
+
# Event objects of this form may be returned from a protocol binding when
|
126
|
+
# it decodes an event with a `datacontenttype` that it does not know how
|
127
|
+
# to interpret. Applications should query {#data_decoded?} to determine
|
128
|
+
# whether the {#data} method returns encoded or decoded data.
|
129
|
+
#
|
130
|
+
# If you provide _neither_ `:data` nor `:data_encoded`, the event will
|
131
|
+
# have no payload data. Both {#data} and {#data_encoded} will return nil,
|
132
|
+
# and {#data_decoded?} will return false. (Additionally, {#data?} will
|
133
|
+
# return false to signal the absence of any data.)
|
134
|
+
#
|
135
|
+
# @param set_attributes [Hash] The data and attributes, as a hash.
|
136
|
+
# (Also available using the deprecated keyword `attributes`.)
|
69
137
|
# @param args [keywords] The data and attributes, as keyword arguments.
|
70
138
|
#
|
71
|
-
def initialize attributes: nil, **args
|
72
|
-
interpreter = FieldInterpreter.new attributes || args
|
139
|
+
def initialize set_attributes: nil, attributes: nil, **args
|
140
|
+
interpreter = FieldInterpreter.new set_attributes || attributes || args
|
73
141
|
@spec_version = interpreter.spec_version ["specversion", "spec_version"], accept: /^1(\.|$)/
|
74
142
|
@id = interpreter.string ["id"], required: true
|
75
143
|
@source = interpreter.uri ["source"], required: true
|
76
144
|
@type = interpreter.string ["type"], required: true
|
145
|
+
@data_encoded = interpreter.string ["data_encoded"], allow_empty: true
|
77
146
|
@data = interpreter.data_object ["data"]
|
147
|
+
if @data == FieldInterpreter::UNDEFINED
|
148
|
+
@data = @data_encoded
|
149
|
+
@data_decoded = false
|
150
|
+
else
|
151
|
+
@data_decoded = true
|
152
|
+
end
|
78
153
|
@data_content_type = interpreter.content_type ["datacontenttype", "data_content_type"]
|
79
154
|
@data_schema = interpreter.uri ["dataschema", "data_schema"]
|
80
155
|
@subject = interpreter.string ["subject"]
|
@@ -93,8 +168,14 @@ module CloudEvents
|
|
93
168
|
# @return [FunctionFramework::CloudEvents::Event]
|
94
169
|
#
|
95
170
|
def with **changes
|
96
|
-
|
97
|
-
|
171
|
+
changes = Utils.keys_to_strings changes
|
172
|
+
attributes = @attributes.dup
|
173
|
+
if changes.key?("data") || changes.key?("data_encoded")
|
174
|
+
attributes.delete "data"
|
175
|
+
attributes.delete "data_encoded"
|
176
|
+
end
|
177
|
+
attributes.merge! changes
|
178
|
+
V1.new set_attributes: attributes
|
98
179
|
end
|
99
180
|
|
100
181
|
##
|
@@ -160,19 +241,61 @@ module CloudEvents
|
|
160
241
|
alias specversion spec_version
|
161
242
|
|
162
243
|
##
|
163
|
-
# The event
|
244
|
+
# The event `data` field, or `nil` if there is no data.
|
245
|
+
#
|
246
|
+
# This may return the data as an encoded string _or_ as a decoded Ruby
|
247
|
+
# object. The {#data_decoded?} method specifies whether the `data` value
|
248
|
+
# is decoded or encoded.
|
249
|
+
#
|
250
|
+
# In most cases, {#data} returns a decoded value, unless the event was
|
251
|
+
# received from a source that could not decode the content. For example,
|
252
|
+
# most protocol bindings understand how to decode JSON, so an event
|
253
|
+
# received with a {#data_content_type} of `application/json` will usually
|
254
|
+
# return a decoded object (usually a Hash) from {#data}.
|
164
255
|
#
|
165
|
-
#
|
166
|
-
# * Binary data, represented by a `String` using the `ASCII-8BIT`
|
167
|
-
# encoding.
|
168
|
-
# * A string in some other encoding such as `UTF-8` or `US-ASCII`.
|
169
|
-
# * Any JSON data type, such as a Boolean, Integer, Array, Hash, or
|
170
|
-
# `nil`.
|
256
|
+
# See also {#data_encoded} and {#data_decoded?}.
|
171
257
|
#
|
172
|
-
# @return [Object]
|
258
|
+
# @return [Object] if containing decoded data
|
259
|
+
# @return [String] if containing encoded data
|
260
|
+
# @return [nil] if there is no data
|
173
261
|
#
|
174
262
|
attr_reader :data
|
175
263
|
|
264
|
+
##
|
265
|
+
# The encoded string representation of the data, i.e. its raw form used
|
266
|
+
# when encoding an event for transmission. This may be `nil` if there is
|
267
|
+
# no data, or if the encoded form is not known.
|
268
|
+
#
|
269
|
+
# See also {#data}.
|
270
|
+
#
|
271
|
+
# @return [String,nil]
|
272
|
+
#
|
273
|
+
attr_reader :data_encoded
|
274
|
+
|
275
|
+
##
|
276
|
+
# Indicates whether the {#data} field returns decoded data.
|
277
|
+
#
|
278
|
+
# @return [true] if {#data} returns a decoded Ruby object
|
279
|
+
# @return [false] if {#data} returns an encoded string or if the event
|
280
|
+
# has no data.
|
281
|
+
#
|
282
|
+
def data_decoded?
|
283
|
+
@data_decoded
|
284
|
+
end
|
285
|
+
|
286
|
+
##
|
287
|
+
# Indicates whether the data field is present. If there is no data,
|
288
|
+
# {#data} will return `nil`, and {#data_decoded?} will return false.
|
289
|
+
#
|
290
|
+
# Generally, if there is no data, the {#data_content_type} field should
|
291
|
+
# also be absent, but this is not enforced.
|
292
|
+
#
|
293
|
+
# @return [boolean]
|
294
|
+
#
|
295
|
+
def data?
|
296
|
+
!@data.nil? || @data_decoded
|
297
|
+
end
|
298
|
+
|
176
299
|
##
|
177
300
|
# The optional `datacontenttype` field as a {CloudEvents::ContentType}
|
178
301
|
# object, or `nil` if the field is absent.
|