pbbuilder 0.18.0 → 0.19.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/.github/workflows/test.yml +4 -13
- data/Appraisals +3 -3
- data/CHANGELOG.md +9 -0
- data/Gemfile +0 -2
- data/README.md +19 -18
- data/Rakefile +22 -5
- data/gemfiles/rails_6_1.gemfile +0 -1
- data/gemfiles/rails_7_0.gemfile +0 -1
- data/gemfiles/{rails_7_1.gemfile → rails_7_2.gemfile} +1 -2
- data/lib/pbbuilder/errors.rb +2 -4
- data/lib/pbbuilder/template.rb +19 -20
- data/lib/pbbuilder.rb +24 -11
- data/pbbuilder.gemspec +1 -1
- data/test/pbbuilder_template_test.rb +2 -2
- data/test/pbbuilder_test.rb +1 -1
- data/test/test_helper.rb +6 -0
- metadata +4 -5
- data/lib/pbbuilder/pbbuilder.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ea3598ad1ed31172d0b3154c6968649f63073f23de0d94abf191a07dbdbf4e0
|
4
|
+
data.tar.gz: 7285883ae069eeff4f1860eb9b4c4a727585e6762b3bfd974ce1fb9e51928086
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e051d79882379fb30f3f0b4bab503e6591034d1cc16639918d685a0ef19e6f7cc42ea224954bf755db739f6a2b2c2c86a8c7666e23065ce337aafb862486b4f6
|
7
|
+
data.tar.gz: 90f2266161a9a101fd4b67afb71130a009b17ec9a5139dc583db18d02a1a32a2bd7730f1ea872c3d4b77a4d64f953b1a34e72cb35f845dc6a879f117f7c3c5ec
|
data/.github/workflows/test.yml
CHANGED
@@ -14,21 +14,12 @@ jobs:
|
|
14
14
|
fail-fast: false
|
15
15
|
matrix:
|
16
16
|
ruby: ["3.0", "3.1", "3.2", "3.3"]
|
17
|
-
|
18
|
-
|
17
|
+
gemfile: [ "rails_6_1", "rails_7_0", "rails_7_2"]
|
18
|
+
exclude:
|
19
|
+
- ruby: "3.0"
|
20
|
+
gemfile: "rails_7_2"
|
19
21
|
experimental: [false]
|
20
22
|
|
21
|
-
#include:
|
22
|
-
# - ruby: '2.7'
|
23
|
-
# gemfile: rails_head
|
24
|
-
# experimental: true
|
25
|
-
# - ruby: '3.0'
|
26
|
-
# gemfile: rails_head
|
27
|
-
# experimental: true
|
28
|
-
# - ruby: '3.1'
|
29
|
-
# gemfile: rails_head
|
30
|
-
# experimental: true
|
31
|
-
|
32
23
|
steps:
|
33
24
|
- uses: actions/checkout@v3
|
34
25
|
|
data/Appraisals
CHANGED
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file.
|
|
3
3
|
|
4
4
|
This format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
5
5
|
|
6
|
+
## 0.19.0
|
7
|
+
### Added
|
8
|
+
- Add support for rails 7.2, but leave out rails 7.1 support. This is because ActionView has a breaking bug in 7.1 that renders the template back as a string
|
9
|
+
instead of an object, like we need for Pbbuilder https://github.com/rails/rails/pull/51023
|
10
|
+
|
11
|
+
## 0.18.0
|
12
|
+
### Added
|
13
|
+
- Allow literal assignment of protos to fields
|
14
|
+
|
6
15
|
## 0.17.0
|
7
16
|
### Changed
|
8
17
|
- Instead of appending to repeated enum message, we're replacing it to avoid issues in case output will be rendered twice
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,22 +1,19 @@
|
|
1
1
|
# Pbbuilder
|
2
|
-
PBBuilder generates [Protobuf](https://developers.google.com/protocol-buffers) Messages with a simple DSL similar to [JBuilder](https://rubygems.org/gems/jbuilder) gem.
|
2
|
+
PBBuilder generates [Protobuf](https://developers.google.com/protocol-buffers) Messages with a simple DSL similar to the [JBuilder](https://rubygems.org/gems/jbuilder) gem.
|
3
3
|
|
4
4
|
|
5
|
-
At least Rails 6.1 is required.
|
6
|
-
|
7
|
-
|
8
|
-
> There currently is a regression in ActionView (the part of Rails which renders) that forces rendered objects into strings. This is only present
|
9
|
-
> in Rails 7.1, and is fixed in Rails. However, a 7.1 gem containing the fix hasn't been released yet. For the moment you should refrain
|
10
|
-
> from using pbbuilder and rails-twirp with Rails 7.1 and wait for the next version to be released.
|
5
|
+
At least Rails 6.1 is required and rails 7.1 is currently not supported.
|
6
|
+
There currently is a regression in ActionView (the part of Rails which renders) that forces rendered objects into strings, but for Pbbuilder we need the raw objects.
|
7
|
+
This is only present in Rails 7.1, and a fix is released in Rails 7.2. https://github.com/rails/rails/pull/51023
|
11
8
|
|
12
9
|
## Compatibility with jBuilder
|
13
10
|
We don't aim to have 100% compitability and coverage with jbuilder gem, but we closely follow jbuilder's API design to maintain familiarity.
|
14
11
|
|
15
12
|
| | Jbuilder | Pbbuilder |
|
16
13
|
|---|---|---|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
| set! | ✅ | ✅ |
|
15
|
+
| cache! | ✅ | ✅ |
|
16
|
+
| cache_if! | ✅ | ✅ |
|
20
17
|
| cache_root! | ✅| |
|
21
18
|
| fragment cache | ✅| ✅ |
|
22
19
|
| extract! | ✅ | ✅ |
|
@@ -25,7 +22,7 @@ We don't aim to have 100% compitability and coverage with jbuilder gem, but we c
|
|
25
22
|
| array! | ✅ | |
|
26
23
|
| .call | ✅ | |
|
27
24
|
|
28
|
-
Due to protobuf message implementation, there is absolutely no need to implement support for `deep_format_keys!`, `key_format!`, `key_format`, `deep_format_keys`, `ignore_nil!`, `ignore_nil!`, `nil`. So those would never be added.
|
25
|
+
Due to the protobuf message implementation, there is absolutely no need to implement support for `deep_format_keys!`, `key_format!`, `key_format`, `deep_format_keys`, `ignore_nil!`, `ignore_nil!`, `nil`. So those would never be added.
|
29
26
|
|
30
27
|
## Usage
|
31
28
|
The main difference is that it can use introspection to figure out what kind of protobuf message it needs to create.
|
@@ -61,7 +58,7 @@ pb.phone_number account.phone_number
|
|
61
58
|
pb.tag account.tag
|
62
59
|
```
|
63
60
|
|
64
|
-
|
61
|
+
can be rewritten to a shorter version with the use of `extract!`.
|
65
62
|
```
|
66
63
|
pb.extract! account, :id, :phone_number, :tag
|
67
64
|
```
|
@@ -80,7 +77,7 @@ Using partial while passing a variable to it
|
|
80
77
|
pb.account partial: "account", account: @account
|
81
78
|
```
|
82
79
|
|
83
|
-
Here is way to use partials with collection while passing a variable to it
|
80
|
+
Here is a way to use partials with a collection while passing a variable to it
|
84
81
|
|
85
82
|
```
|
86
83
|
pb.accounts @accounts, partial: "account", as: account
|
@@ -96,7 +93,7 @@ pb.friends partial: "racers/racer", as: :racer, collection: @racers
|
|
96
93
|
pb.friends "racers/racer", as: :racer, collection: @racers
|
97
94
|
```
|
98
95
|
|
99
|
-
And there are other ways, that don't use
|
96
|
+
And there are other ways, that don't use CollectionRenderer
|
100
97
|
```ruby
|
101
98
|
pb.partial! @racer, racer: Racer.new(123, "Chris Harris", friends)
|
102
99
|
```
|
@@ -105,7 +102,7 @@ pb.friends @friends, partial: "racers/racer", as: :racer
|
|
105
102
|
```
|
106
103
|
|
107
104
|
### Caching
|
108
|
-
|
105
|
+
It uses Rails.cache and works like caching in HTML templates:
|
109
106
|
|
110
107
|
```
|
111
108
|
pb.cache! "cache-key", expires_in: 10.minutes do
|
@@ -121,7 +118,7 @@ pb.cache_if! !admin?, "cache-key", expires_in: 10.minutes do
|
|
121
118
|
end
|
122
119
|
```
|
123
120
|
|
124
|
-
Fragment caching currently works through ActionView::CollectionRenderer and can be used
|
121
|
+
Fragment caching currently works through ActionView::CollectionRenderer and can only be used with the following syntax:
|
125
122
|
|
126
123
|
```ruby
|
127
124
|
pb.friends partial: "racers/racer", as: :racer, collection: @racers, cached: true
|
@@ -151,10 +148,14 @@ $ gem install pbbuilder
|
|
151
148
|
|
152
149
|
When debugging, make sure to prepend `::Kernel` to any calls such as `puts` as otherwise the code will think you're trying to add another attribute into protobuf object.
|
153
150
|
|
154
|
-
In case
|
151
|
+
In case you're looking to use breakpoints (for debugging purposes via `binding.pry` for instance), let Pbbuilder inherit from `Object` instead of `BasicObject`]
|
152
|
+
Seen in:
|
153
|
+
[Pbbuilder](lib/pbbuilder/pbbuilder.rb)
|
154
|
+
[Errors](lib/pbbuilder/errors.rb)
|
155
155
|
|
156
156
|
## Testing
|
157
|
-
Running `bundle exec appraisal rake test` locally will run entire testsuit with all
|
157
|
+
Running `bundle exec appraisal rake test` locally will run the entire testsuit with all versions of rails.
|
158
|
+
To run tests only for a certain rails version do the following `bundle exec appraisal rails-7-0 rake test`
|
158
159
|
|
159
160
|
To run only one tests from file - use `m` utility. Like this:
|
160
161
|
`bundle exec appraisal rails-7-0 m test/pbbuilder_template_test.rb:182`
|
data/Rakefile
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "bundler/setup"
|
4
3
|
require "bundler/gem_tasks"
|
5
4
|
require "rake/testtask"
|
6
5
|
|
@@ -11,10 +10,28 @@ if !ENV["APPRAISAL_INITIALIZED"] && !ENV["CI"]
|
|
11
10
|
else
|
12
11
|
Rake::TestTask.new(:test) do |t|
|
13
12
|
t.libs << "test"
|
14
|
-
t.
|
15
|
-
|
16
|
-
|
13
|
+
t.libs << "lib"
|
14
|
+
|
15
|
+
# Running specific tests with line numbers, like with rails test, is not supported by default in rake.
|
16
|
+
# By setting the TESTOPS env var we can however specify the name of a single test with underscores instead of spaces.
|
17
|
+
# So run your single test by calling for ex:
|
18
|
+
#
|
19
|
+
# rake test /Users/sebastian/projects/cheddar/rails-twirp/test/ping_controller_test.rb "uncaught errors should bubble up to the test"
|
20
|
+
|
21
|
+
file_name = ARGV[1]
|
22
|
+
test_name = ARGV[2]&.tr(" ", "_")
|
23
|
+
|
24
|
+
ENV["TESTOPTS"] = "--verbose"
|
25
|
+
|
26
|
+
t.test_files = if file_name
|
27
|
+
if test_name
|
28
|
+
ENV["TESTOPTS"] += " --name=test_#{test_name}"
|
29
|
+
end
|
30
|
+
[file_name]
|
31
|
+
else
|
32
|
+
FileList["test/**/*_test.rb"]
|
33
|
+
end
|
17
34
|
end
|
18
35
|
|
19
36
|
task default: :test
|
20
|
-
end
|
37
|
+
end
|
data/gemfiles/rails_6_1.gemfile
CHANGED
data/gemfiles/rails_7_0.gemfile
CHANGED
data/lib/pbbuilder/errors.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
class Pbbuilder
|
3
|
+
class Pbbuilder < BasicObject
|
6
4
|
class MergeError < ::StandardError
|
7
5
|
def self.build(current_value, updates)
|
8
6
|
message = "Can't merge #{updates.inspect} into #{current_value.inspect}"
|
9
7
|
self.new(message)
|
10
8
|
end
|
11
9
|
end
|
12
|
-
end
|
10
|
+
end
|
data/lib/pbbuilder/template.rb
CHANGED
@@ -17,6 +17,7 @@ class PbbuilderTemplate < Pbbuilder
|
|
17
17
|
end
|
18
18
|
|
19
19
|
# Render a partial. Can be called as:
|
20
|
+
#
|
20
21
|
# pb.partial! "name/of_partial", argument: 123
|
21
22
|
# pb.partial! "name/of_partial", locals: {argument: 123}
|
22
23
|
# pb.partial! partial: "name/of_partial", argument: 123
|
@@ -30,7 +31,7 @@ class PbbuilderTemplate < Pbbuilder
|
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
|
-
#
|
34
|
+
# Sets the value in the message field.
|
34
35
|
#
|
35
36
|
# @example
|
36
37
|
# pb.friends @friends, partial: "friend", as: :friend
|
@@ -39,31 +40,30 @@ class PbbuilderTemplate < Pbbuilder
|
|
39
40
|
# pb.friends "racers/racer", as: :racer, collection: [Racer.new(1, "Johnny Test", []), Racer.new(2, "Max Verstappen", [])]
|
40
41
|
|
41
42
|
def set!(field, *args, **kwargs, &block)
|
42
|
-
# If partial options are being passed, we render a submessage with a partial
|
43
|
+
# If any partial options are being passed, we render a submessage with a partial
|
43
44
|
if kwargs.has_key?(:partial)
|
44
45
|
if args.one? && kwargs.has_key?(:as)
|
45
|
-
#
|
46
|
+
# Example syntax that should end up here:
|
46
47
|
# pb.friends @friends, partial: "friend", as: :friend
|
47
48
|
# Call set! on the super class, passing in a block that renders a partial for every element
|
48
49
|
super(field, *args) do |element|
|
49
50
|
_set_inline_partial(element, kwargs)
|
50
51
|
end
|
51
52
|
elsif kwargs.has_key?(:collection) && kwargs.has_key?(:as)
|
52
|
-
#
|
53
|
+
# Example syntax that should end up here:
|
53
54
|
# pb.friends partial: "racers/racer", as: :racer, collection: [Racer.new(1, "Johnny Test", []), Racer.new(2, "Max Verstappen", [])]
|
54
55
|
|
55
56
|
_render_collection_with_options(field, kwargs[:collection], kwargs)
|
56
57
|
else
|
57
|
-
#
|
58
|
+
# Example syntax that should end up here:
|
58
59
|
# pb.best_friend partial: "person", person: @best_friend
|
59
|
-
|
60
60
|
super(field, *args) do
|
61
61
|
_render_partial_with_options(kwargs)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
else
|
65
65
|
if args.one? && kwargs.has_key?(:collection) && kwargs.has_key?(:as)
|
66
|
-
#
|
66
|
+
# Example syntax that should end up here:
|
67
67
|
# pb.friends "racers/racer", as: :racer, collection: [Racer.new(1, "Johnny Test", []), Racer.new(2, "Max Verstappen", [])]
|
68
68
|
_render_collection_with_options(field, kwargs[:collection], kwargs.merge(partial: args.first))
|
69
69
|
else
|
@@ -72,7 +72,7 @@ class PbbuilderTemplate < Pbbuilder
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
# Caches fragment of message. Can be called like the following:
|
75
|
+
# Caches a fragment of a message with a given cache key. Can be called like the following:
|
76
76
|
# 'pb.cache! "cache-key" do; end'
|
77
77
|
# 'pb.cache! "cache-key", expire_in: 1.min do; end'
|
78
78
|
#
|
@@ -107,16 +107,16 @@ class PbbuilderTemplate < Pbbuilder
|
|
107
107
|
|
108
108
|
private
|
109
109
|
|
110
|
-
# Uses ActionView::CollectionRenderer to render collection effectively and to use rails built
|
110
|
+
# Uses ActionView::CollectionRenderer to render the collection effectively and to use rails' built-in fragment caching support.
|
111
111
|
#
|
112
|
-
# The way recursive rendering works is that the CollectionRenderer needs to be aware of the node
|
113
|
-
# There is no need to know the entire "stack" of nodes. ActionView::CollectionRenderer
|
114
|
-
#
|
112
|
+
# The way recursive rendering works is that the CollectionRenderer needs to be aware of the node it's currently rendering and it's parent node.
|
113
|
+
# There is no need to know the entire "stack" of nodes. ActionView::CollectionRenderer will traverse to the bottom node, render it first and then go one level up in the stack.
|
114
|
+
# Rinse and repeat until the entire stack is rendered.
|
115
115
|
|
116
116
|
# CollectionRenderer uses locals[:pb] to render the partial as a protobuf message,
|
117
117
|
# but also needs locals[:pb_parent] to apply the rendered partial to the top level protobuf message.
|
118
118
|
|
119
|
-
# This logic can be found in CollectionRenderer#build_rendered_collection method that we overwrote.
|
119
|
+
# This logic can be found in the CollectionRenderer#build_rendered_collection method that we overwrote.
|
120
120
|
def _render_collection_with_options(field, collection, options)
|
121
121
|
partial = options[:partial]
|
122
122
|
|
@@ -128,15 +128,15 @@ class PbbuilderTemplate < Pbbuilder
|
|
128
128
|
options[:locals].merge!(field: field)
|
129
129
|
|
130
130
|
if options.has_key?(:layout)
|
131
|
-
raise ::NotImplementedError, "The `:layout' option is not supported in collection rendering."
|
131
|
+
::Kernel.raise ::NotImplementedError, "The `:layout' option is not supported in collection rendering."
|
132
132
|
end
|
133
133
|
|
134
134
|
if options.has_key?(:spacer_template)
|
135
|
-
raise ::NotImplementedError, "The `:spacer_template' option is not supported in collection rendering."
|
135
|
+
::Kernel.raise ::NotImplementedError, "The `:spacer_template' option is not supported in collection rendering."
|
136
136
|
end
|
137
137
|
|
138
138
|
CollectionRenderer
|
139
|
-
.new(@context.lookup_context, options) { |&block| _scope(message[field.to_s]
|
139
|
+
.new(@context.lookup_context, options) { |&block| _scope(message[field.to_s], &block) }
|
140
140
|
.render_collection_with_partial(collection, partial, @context, nil)
|
141
141
|
end
|
142
142
|
|
@@ -172,10 +172,9 @@ class PbbuilderTemplate < Pbbuilder
|
|
172
172
|
begin
|
173
173
|
::Rails.cache.write(key, value, options)
|
174
174
|
rescue ::SystemCallError
|
175
|
-
# In case ActiveSupport::Cache::FileStore in Rails is used as a cache,
|
176
|
-
# File.atomic_write can have a race condition and
|
177
|
-
#
|
178
|
-
# error and returning a value.
|
175
|
+
# In case `ActiveSupport::Cache::FileStore` in Rails is used as a cache,
|
176
|
+
# `File.atomic_write` can have a race condition and fails to rename temporary file.
|
177
|
+
# We're attempting to recover from that by catching this specific error and returning a value.
|
179
178
|
#
|
180
179
|
# @see https://github.com/rails/rails/pull/44151
|
181
180
|
# @see https://github.com/rails/rails/blob/main/activesupport/lib/active_support/core_ext/file/atomic.rb#L50
|
data/lib/pbbuilder.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "pbbuilder/
|
4
|
-
require 'pbbuilder/errors'
|
3
|
+
require "pbbuilder/errors"
|
5
4
|
require "pbbuilder/protobuf_extension"
|
6
5
|
require "pbbuilder/railtie" if defined?(Rails)
|
7
6
|
|
8
|
-
|
9
|
-
# Pbbuilder makes it easy to create a protobuf message using the builder pattern
|
7
|
+
# Pbbuilder makes it easy to create a protobuf message using the builder pattern.
|
10
8
|
# It is heavily inspired by jbuilder
|
11
9
|
#
|
12
10
|
# Given this example message definition:
|
@@ -15,8 +13,10 @@ require "pbbuilder/railtie" if defined?(Rails)
|
|
15
13
|
# repeated Person friends = 2;
|
16
14
|
# }
|
17
15
|
#
|
18
|
-
# You
|
16
|
+
# You can use Pbbuilder as follows:
|
17
|
+
#
|
19
18
|
# person = RPC::Person.new
|
19
|
+
#
|
20
20
|
# Pbbuilder.new(person) do |pb|
|
21
21
|
# pb.name "Hello"
|
22
22
|
# pb.friends [1, 2, 3] do |number|
|
@@ -29,7 +29,7 @@ require "pbbuilder/railtie" if defined?(Rails)
|
|
29
29
|
# It basically works exactly like jbuilder. The main difference is that it can use introspection to figure out what kind
|
30
30
|
# of protobuf message it needs to create.
|
31
31
|
|
32
|
-
class Pbbuilder
|
32
|
+
class Pbbuilder < BasicObject
|
33
33
|
def initialize(message)
|
34
34
|
@message = message
|
35
35
|
|
@@ -48,11 +48,15 @@ class Pbbuilder
|
|
48
48
|
!!_descriptor_for_field(field)
|
49
49
|
end
|
50
50
|
|
51
|
+
# When calling for ex: response.drivers, where response is a Google::Protobuf object, 'drivers' is not a method on that. These
|
52
|
+
# methods (or messages in our case) get added here. This is of course based on what kind of message it is. Singular, an array
|
53
|
+
# (repeated) etc. with their arguments.
|
51
54
|
def set!(field, *args, &block)
|
52
55
|
name = field.to_s
|
53
56
|
descriptor = _descriptor_for_field(name)
|
54
|
-
::Kernel.raise ::ArgumentError, "Unknown field #{name}" if descriptor.nil?
|
57
|
+
::Kernel.raise ::ArgumentError, "Unknown field: #{name}" if descriptor.nil?
|
55
58
|
|
59
|
+
# An block is used to pass on it's children
|
56
60
|
if ::Kernel.block_given?
|
57
61
|
::Kernel.raise ::ArgumentError, "can't pass block to non-message field" unless descriptor.type == :message
|
58
62
|
|
@@ -66,9 +70,11 @@ class Pbbuilder
|
|
66
70
|
# example syntax that should end up here:
|
67
71
|
# pb.field { pb.name "hello" }
|
68
72
|
::Kernel.raise ::ArgumentError, "wrong number of arguments (expected 0)" unless args.empty?
|
73
|
+
|
69
74
|
message = (@message[name] ||= _new_message_from_descriptor(descriptor))
|
70
75
|
_scope(message, &block)
|
71
76
|
end
|
77
|
+
# No block given, but with 1 argument
|
72
78
|
elsif args.length == 1
|
73
79
|
arg = args.first
|
74
80
|
if descriptor.label == :repeated
|
@@ -106,7 +112,7 @@ class Pbbuilder
|
|
106
112
|
else
|
107
113
|
# example syntax that should end up here:
|
108
114
|
# pb.field "value"
|
109
|
-
|
115
|
+
|
110
116
|
@message[name] = arg
|
111
117
|
end
|
112
118
|
else
|
@@ -128,6 +134,8 @@ class Pbbuilder
|
|
128
134
|
end
|
129
135
|
end
|
130
136
|
|
137
|
+
# Shorthand command for getting a few attributes from an object.
|
138
|
+
# pb.extract! racer, :name, :id, :age
|
131
139
|
def extract!(element, *args)
|
132
140
|
args.each { |arg| @message[arg.to_s] = element.send(arg) }
|
133
141
|
end
|
@@ -181,6 +189,7 @@ class Pbbuilder
|
|
181
189
|
@message
|
182
190
|
end
|
183
191
|
|
192
|
+
# @param field string
|
184
193
|
def new_message_for(field)
|
185
194
|
descriptor = _descriptor_for_field(field)
|
186
195
|
::Kernel.raise ::ArgumentError, "Unknown field #{field}" if descriptor.nil?
|
@@ -190,11 +199,14 @@ class Pbbuilder
|
|
190
199
|
|
191
200
|
private
|
192
201
|
|
202
|
+
# Lookup the field name (or 'attribute' name, for ex "best_friend") on the Google descriptor (Google::Protobuf::Descriptor) of our
|
203
|
+
# message object.
|
204
|
+
# @param field string
|
193
205
|
def _descriptor_for_field(field)
|
194
206
|
@message.class.descriptor.lookup(field.to_s)
|
195
207
|
end
|
196
208
|
|
197
|
-
# Appends protobuf
|
209
|
+
# Appends protobuf objects to our 'repeated' attribute. This can create a list of items to a repeated field.
|
198
210
|
#
|
199
211
|
# @param name string
|
200
212
|
# @param descriptor Google::Protobuf::FieldDescriptor
|
@@ -210,7 +222,8 @@ class Pbbuilder
|
|
210
222
|
@message[name].push(*elements)
|
211
223
|
end
|
212
224
|
|
213
|
-
# Yields
|
225
|
+
# Yields a Protobuf object in the scope of message and provided values.
|
226
|
+
# This will 'assign' the field values as it were to the message attributes.
|
214
227
|
#
|
215
228
|
# @param message Google::Protobuf::(field_type)
|
216
229
|
def _scope(message)
|
@@ -222,7 +235,7 @@ class Pbbuilder
|
|
222
235
|
@message = old_message
|
223
236
|
end
|
224
237
|
|
225
|
-
#
|
238
|
+
# Builds up an empty protobuf message based on the given descriptor.
|
226
239
|
#
|
227
240
|
# @param descriptor Google::Protobuf::FieldDescriptor
|
228
241
|
def _new_message_from_descriptor(descriptor)
|
data/pbbuilder.gemspec
CHANGED
@@ -57,7 +57,7 @@ class PbbuilderTemplateTest < ActiveSupport::TestCase
|
|
57
57
|
test "collection partial with fragment caching enabled" do
|
58
58
|
template = <<-PBBUILDER
|
59
59
|
racers = [Racer.new(1, "Johnny Test", [], nil, API::Asset.new(url: "https://google.com/test1.svg")), Racer.new(2, "Max Verstappen", [])]
|
60
|
-
pb.friends partial: "racers/racer",
|
60
|
+
pb.friends partial: "racers/racer", collection: racers, cached: true, as: :racer
|
61
61
|
PBBUILDER
|
62
62
|
result = render(template)
|
63
63
|
|
@@ -83,7 +83,7 @@ class PbbuilderTemplateTest < ActiveSupport::TestCase
|
|
83
83
|
end
|
84
84
|
|
85
85
|
test "render collections with partial as arg" do
|
86
|
-
skip("This will be addressed in future version of
|
86
|
+
skip("This will be addressed in a future version of this gem")
|
87
87
|
result = render('pb.friends "racers/racer", as: :racer, collection: [Racer.new(1, "Johnny Test", []), Racer.new(2, "Max Verstappen", [])]')
|
88
88
|
|
89
89
|
assert_equal 2, result.friends.count
|
data/test/pbbuilder_test.rb
CHANGED
@@ -62,7 +62,7 @@ class PbbuilderTest < ActiveSupport::TestCase
|
|
62
62
|
|
63
63
|
assert_equal(["ok", "that's"], p.field_mask.paths)
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
test "sets the last value of the repeated field to be the only value" do
|
67
67
|
person = Pbbuilder.new(API::Person.new) do |pb|
|
68
68
|
pb.field_mask do
|
data/test/test_helper.rb
CHANGED
@@ -55,10 +55,16 @@ class << Rails
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
Pbbuilder::CollectionRenderer.collection_cache = Rails.cache
|
59
|
+
|
58
60
|
class Racer < Struct.new(:id, :name, :friends, :best_friend, :logo)
|
59
61
|
extend ActiveModel::Naming
|
60
62
|
include ActiveModel::Conversion
|
61
63
|
|
64
|
+
def cache_key
|
65
|
+
"racer-#{id}"
|
66
|
+
end
|
67
|
+
|
62
68
|
# Fragment caching needs to know, if record could be persisted. We set it to false, this is a default in ActiveModel::API.
|
63
69
|
def persisted?
|
64
70
|
false
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pbbuilder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.19.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bouke van der Bijl
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: google-protobuf
|
@@ -89,13 +89,12 @@ files:
|
|
89
89
|
- gemfiles/rails_6_1.gemfile
|
90
90
|
- gemfiles/rails_7.gemfile
|
91
91
|
- gemfiles/rails_7_0.gemfile
|
92
|
-
- gemfiles/
|
92
|
+
- gemfiles/rails_7_2.gemfile
|
93
93
|
- gemfiles/rails_head.gemfile
|
94
94
|
- lib/pbbuilder.rb
|
95
95
|
- lib/pbbuilder/collection_renderer.rb
|
96
96
|
- lib/pbbuilder/errors.rb
|
97
97
|
- lib/pbbuilder/handler.rb
|
98
|
-
- lib/pbbuilder/pbbuilder.rb
|
99
98
|
- lib/pbbuilder/protobuf_extension.rb
|
100
99
|
- lib/pbbuilder/railtie.rb
|
101
100
|
- lib/pbbuilder/template.rb
|
@@ -123,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
122
|
- !ruby/object:Gem::Version
|
124
123
|
version: '0'
|
125
124
|
requirements: []
|
126
|
-
rubygems_version: 3.
|
125
|
+
rubygems_version: 3.5.18
|
127
126
|
signing_key:
|
128
127
|
specification_version: 4
|
129
128
|
summary: Generate Protobuf Messages with a simple DSL similar to JBuilder
|
data/lib/pbbuilder/pbbuilder.rb
DELETED