props_template 0.35.0 → 0.37.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/README.md +118 -17
- data/lib/props_template/base.rb +26 -0
- data/lib/props_template/extensions/partial_renderer.rb +1 -1
- data/lib/props_template/version.rb +1 -1
- data/lib/props_template.rb +8 -2
- metadata +21 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ecdcee486c14966bbb3259a5b213631b3cd29f14a31a7194a8e9aad1ade31398
|
4
|
+
data.tar.gz: c33d2129e1aa5ba580003c834f828bc48c820120e4ffa66f9eebfc1531fed7a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f11a45290e1c10aa7b526506f305b723928e8414117a6aac637dbdbd95d09ae414cb18ff5c8d74a249cf12bf85f55af5d2d9f83f7846c2c03690fde5d4990bc
|
7
|
+
data.tar.gz: bc476b0780f7448883bd7dfe8316ac837c851d7255420eeb8496730285d68404b64dcf94a45e856acbaefa9788c76d7f1b70722a61316129e9751a16250e8d7c
|
data/README.md
CHANGED
@@ -72,7 +72,7 @@ gem 'props_template'
|
|
72
72
|
and run `bundle`.
|
73
73
|
|
74
74
|
Optionally add the [core ext](#array-core-extension) to an initializer if you
|
75
|
-
want to [dig](#
|
75
|
+
want to [dig](#digging) into your templates.
|
76
76
|
|
77
77
|
```ruby
|
78
78
|
require 'props_template/core_ext'
|
@@ -93,8 +93,7 @@ You can also add a [layout](#layouts).
|
|
93
93
|
|
94
94
|
### json.set! or json.\<your key here\>
|
95
95
|
|
96
|
-
Defines the attribute or structure. All keys are
|
97
|
-
by default. See [Change Key Format](#change-key-format) to change this behavior.
|
96
|
+
Defines the attribute or structure. All keys are not formatted by default. See [Change Key Format](#change-key-format) to change this behavior.
|
98
97
|
|
99
98
|
```ruby
|
100
99
|
json.set! :authorDetails, {...options} do
|
@@ -153,9 +152,36 @@ The difference between the block form and inline form is
|
|
153
152
|
1. The block form is an internal node. Functionality such as Partials,
|
154
153
|
Deferment and other [options](#options) are only available on the
|
155
154
|
block form.
|
156
|
-
2. The inline form is considered a leaf node, and you can only [
|
155
|
+
2. The inline form is considered a leaf node, and you can only [dig](#digging)
|
157
156
|
for internal nodes.
|
158
157
|
|
158
|
+
### json.extract!
|
159
|
+
Extracts attributes from object or hash in 1 line
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
# without extract!
|
163
|
+
json.id user.id
|
164
|
+
json.email user.email
|
165
|
+
json.firstName user.first_name
|
166
|
+
|
167
|
+
# with extract!
|
168
|
+
json.extract! user, :id, :email, :first_name
|
169
|
+
|
170
|
+
# => {"id" => 1, "email" => "email@gmail.com", "first_name" => "user"}
|
171
|
+
|
172
|
+
# with extract! with key transformation
|
173
|
+
json.extract! user, :id, [:first_name, :firstName], [:last_name, :lastName]
|
174
|
+
|
175
|
+
# => {"id" => 1, "firstName" => "user", "lastName" => "last"}
|
176
|
+
```
|
177
|
+
|
178
|
+
The inline form defines object and attributes
|
179
|
+
|
180
|
+
| Parameter | Notes |
|
181
|
+
| :--- | :--- |
|
182
|
+
| object | An object |
|
183
|
+
| attributes | A list of attributes |
|
184
|
+
|
159
185
|
### json.array!
|
160
186
|
Generates an array of json objects.
|
161
187
|
|
@@ -176,7 +202,7 @@ end
|
|
176
202
|
| collection | A collection that responds to `member_at` and `member_by` |
|
177
203
|
| options | Additional [options](#options)|
|
178
204
|
|
179
|
-
To support [
|
205
|
+
To support [digging](#digging), any list passed
|
180
206
|
to `array!` MUST implement `member_at(index)` and `member_by(attr, value)`.
|
181
207
|
|
182
208
|
For example, if you were using a delegate:
|
@@ -250,7 +276,7 @@ end
|
|
250
276
|
```
|
251
277
|
|
252
278
|
PropsTemplate does not know what the elements are in your collection. The
|
253
|
-
example above will be fine for [
|
279
|
+
example above will be fine for [digging](#digging)
|
254
280
|
by index, but will raise a `NotImplementedError` if you query by attribute. You
|
255
281
|
may still need to implement `member_by`.
|
256
282
|
|
@@ -291,7 +317,7 @@ end
|
|
291
317
|
### Partials
|
292
318
|
|
293
319
|
Partials are supported. The following will render the file
|
294
|
-
`views/posts/_blog_posts.json.props`, and set a local variable `
|
320
|
+
`views/posts/_blog_posts.json.props`, and set a local variable `post` assigned
|
295
321
|
with @post, which you can use inside the partial.
|
296
322
|
|
297
323
|
```ruby
|
@@ -303,6 +329,7 @@ Usage with arrays:
|
|
303
329
|
|
304
330
|
```ruby
|
305
331
|
# The `as:` option is supported when using `array!`
|
332
|
+
# Without `as:` option you can use blog_post variable (name is based on partial's name) inside partial
|
306
333
|
|
307
334
|
json.posts do
|
308
335
|
json.array! @posts, partial: ["posts/blog_post", locals: {foo: 'bar'}, as: 'post'] do
|
@@ -310,6 +337,35 @@ json.posts do
|
|
310
337
|
end
|
311
338
|
```
|
312
339
|
|
340
|
+
Rendering partials without a key is also supported using `json.partial!`, but use
|
341
|
+
sparingly! `json.partial!` is not optimized for collection rendering and may
|
342
|
+
cause performance problems. Its best used for things like a shared header or footer.
|
343
|
+
|
344
|
+
Do:
|
345
|
+
|
346
|
+
```ruby
|
347
|
+
json.partial! partial: "header", locals: {user: @user} do
|
348
|
+
end
|
349
|
+
```
|
350
|
+
|
351
|
+
or
|
352
|
+
|
353
|
+
```ruby
|
354
|
+
json.posts do
|
355
|
+
json.array! @posts, partial: ["posts/blog_post", locals: {post: @post}] do
|
356
|
+
end
|
357
|
+
end
|
358
|
+
```
|
359
|
+
|
360
|
+
Do NOT:
|
361
|
+
|
362
|
+
```
|
363
|
+
@post.each do |post|
|
364
|
+
json.partial! partial: "post", locals: {post: @post} do
|
365
|
+
end
|
366
|
+
end
|
367
|
+
```
|
368
|
+
|
313
369
|
### Partial Fragments
|
314
370
|
**Note** This is a [SuperglueJS][1] specific functionality.
|
315
371
|
|
@@ -391,7 +447,7 @@ entirely and replace the value with a placeholder. A common use case would be
|
|
391
447
|
tabbed content that does not load until you click the tab.
|
392
448
|
|
393
449
|
When your client receives the payload, you may issue a second request to the
|
394
|
-
same endpoint to fetch any missing nodes. See [
|
450
|
+
same endpoint to fetch any missing nodes. See [digging](#digging)
|
395
451
|
|
396
452
|
There is also an `defer: :auto` option that you can use with [SuperglueJS][1]. [SuperglueJS][1]
|
397
453
|
will use the metadata from `json.deferred!` to issue a `remote` dispatch to fetch
|
@@ -446,7 +502,7 @@ your collection item, and is used for `defer: :auto` to generate a keypath for
|
|
446
502
|
[SuperglueJS][1]. If you are NOT using SuperglueJS, you do not need to do this.
|
447
503
|
|
448
504
|
2. Implement `member_at`, on the [collection](#jsonarray). This will be called
|
449
|
-
by PropsTemplate to when [
|
505
|
+
by PropsTemplate to when [digging](#digging)
|
450
506
|
|
451
507
|
For example:
|
452
508
|
|
@@ -472,7 +528,7 @@ end
|
|
472
528
|
If you are using [SuperglueJS][1], SuperglueJS will, it will automatically kick off
|
473
529
|
`remote(?props_at=posts.some_id=1.contact)` and `remote(?props_at=posts.some_id=2.contact)`.
|
474
530
|
|
475
|
-
##
|
531
|
+
## Digging
|
476
532
|
|
477
533
|
PropsTemplate has the ability to walk the tree you build, skipping execution of
|
478
534
|
untargeted nodes. This feature is useful for selectively updating your frontend
|
@@ -481,7 +537,7 @@ state.
|
|
481
537
|
```ruby
|
482
538
|
traversal_path = ['data', 'details', 'personal']
|
483
539
|
|
484
|
-
json.data(
|
540
|
+
json.data(dig: traversal_path) do
|
485
541
|
json.details do
|
486
542
|
json.employment do
|
487
543
|
...more stuff
|
@@ -515,13 +571,13 @@ The above will output:
|
|
515
571
|
}
|
516
572
|
```
|
517
573
|
|
518
|
-
|
574
|
+
Digging only works with blocks, and will NOT work with Scalars
|
519
575
|
("leaf" values). For example:
|
520
576
|
|
521
577
|
```ruby
|
522
578
|
traversal_path = ['data', 'details', 'personal', 'name'] <- not found
|
523
579
|
|
524
|
-
json.data(
|
580
|
+
json.data(dig: traversal_path) do
|
525
581
|
json.details do
|
526
582
|
json.personal do
|
527
583
|
json.name 'james'
|
@@ -532,12 +588,12 @@ end
|
|
532
588
|
|
533
589
|
## Nodes that do not exist
|
534
590
|
|
535
|
-
Nodes that are not found will remove the branch where
|
591
|
+
Nodes that are not found will remove the branch where digging was enabled on.
|
536
592
|
|
537
593
|
```ruby
|
538
594
|
traversal_path = ['data', 'details', 'does_not_exist']
|
539
595
|
|
540
|
-
json.data(
|
596
|
+
json.data(dig: traversal_path) do
|
541
597
|
json.details do
|
542
598
|
json.personal do
|
543
599
|
json.name 'james'
|
@@ -585,15 +641,60 @@ json.flash flash.to_h
|
|
585
641
|
will render Layout first, then the template when `yield json` is used.
|
586
642
|
|
587
643
|
## Change key format
|
588
|
-
By default, keys are not formatted.
|
589
|
-
|
644
|
+
By default, keys are not formatted. This is intentional. By being explicity with your keys,
|
645
|
+
it makes your views quicker and more easily diggable when working in Javascript land.
|
646
|
+
|
647
|
+
If you must change this behavior, override it in an initializer and cache the value:
|
590
648
|
|
591
649
|
```ruby
|
650
|
+
# default behavior
|
592
651
|
Props::BaseWithExtensions.class_eval do
|
652
|
+
# json.firstValue "first"
|
653
|
+
# json.second_value "second"
|
654
|
+
#
|
655
|
+
# -> { "firstValue" => "first", "second_value" => "second" }
|
593
656
|
def key_format(key)
|
594
657
|
key.to_s
|
595
658
|
end
|
596
659
|
end
|
660
|
+
|
661
|
+
# camelCased behavior
|
662
|
+
Props::BaseWithExtensions.class_eval do
|
663
|
+
# json.firstValue "first"
|
664
|
+
# json.second_value "second"
|
665
|
+
#
|
666
|
+
# -> { "firstValue" => "first", "secondValue" => "second" }
|
667
|
+
def key_format(key)
|
668
|
+
@key_cache ||= {}
|
669
|
+
@key_cache[key] ||= key.to_s.camelize(:lower)
|
670
|
+
@key_cache[key]
|
671
|
+
end
|
672
|
+
|
673
|
+
def result!
|
674
|
+
result = super
|
675
|
+
@key_cache = {}
|
676
|
+
result
|
677
|
+
end
|
678
|
+
end
|
679
|
+
|
680
|
+
# snake_cased behavior
|
681
|
+
Props::BaseWithExtensions.class_eval do
|
682
|
+
# json.firstValue "first"
|
683
|
+
# json.second_value "second"
|
684
|
+
#
|
685
|
+
# -> { "first_value" => "first", "second_value" => "second" }
|
686
|
+
def key_format(key)
|
687
|
+
@key_cache ||= {}
|
688
|
+
@key_cache[key] ||= key.to_s.underscore
|
689
|
+
@key_cache[key]
|
690
|
+
end
|
691
|
+
|
692
|
+
def result!
|
693
|
+
result = super
|
694
|
+
@key_cache = {}
|
695
|
+
result
|
696
|
+
end
|
697
|
+
end
|
597
698
|
```
|
598
699
|
|
599
700
|
## Escape mode
|
data/lib/props_template/base.rb
CHANGED
@@ -105,6 +105,32 @@ module Props
|
|
105
105
|
nil
|
106
106
|
end
|
107
107
|
|
108
|
+
def partial!(**options)
|
109
|
+
@context.render options
|
110
|
+
end
|
111
|
+
|
112
|
+
# json.id item.id
|
113
|
+
# json.value item.value
|
114
|
+
#
|
115
|
+
# json.extract! item, :id, :value
|
116
|
+
#
|
117
|
+
# with key transformation
|
118
|
+
# json.extract! item, :id, [:first_name, :firstName]
|
119
|
+
def extract!(object, *values)
|
120
|
+
values.each do |value|
|
121
|
+
key, attribute = if value.is_a?(Array)
|
122
|
+
[value[1], value[0]]
|
123
|
+
else
|
124
|
+
[value, value]
|
125
|
+
end
|
126
|
+
|
127
|
+
set!(
|
128
|
+
key,
|
129
|
+
object.is_a?(Hash) ? object.fetch(attribute) : object.public_send(attribute)
|
130
|
+
)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
108
134
|
def result!
|
109
135
|
if @scope.nil?
|
110
136
|
@stream.push_object
|
@@ -82,7 +82,7 @@ module Props
|
|
82
82
|
pass_opts[:locals] ||= {}
|
83
83
|
pass_opts[:partial] = partial
|
84
84
|
pass_opts[:formats] = [:json]
|
85
|
-
pass_opts
|
85
|
+
pass_opts[:handlers] = [:props]
|
86
86
|
|
87
87
|
if !(String === partial)
|
88
88
|
raise ArgumentError.new(INVALID_PARTIAL_MESSAGE % partial.inspect)
|
data/lib/props_template.rb
CHANGED
@@ -22,6 +22,8 @@ module Props
|
|
22
22
|
self.template_lookup_options = {handlers: [:props]}
|
23
23
|
|
24
24
|
delegate :result!, :array!,
|
25
|
+
:partial!,
|
26
|
+
:extract!,
|
25
27
|
:deferred!,
|
26
28
|
:fragments!,
|
27
29
|
:set_block_content!,
|
@@ -34,11 +36,15 @@ module Props
|
|
34
36
|
end
|
35
37
|
|
36
38
|
def set!(key, options = {}, &block)
|
37
|
-
if block && options[:search] && !@builder.is_a?(Searcher)
|
39
|
+
if block && (options[:search] || options[:dig]) && !@builder.is_a?(Searcher)
|
40
|
+
search = options[:search] || options[:dig]
|
38
41
|
|
39
42
|
prev_builder = @builder
|
40
|
-
@builder = Searcher.new(self,
|
43
|
+
@builder = Searcher.new(self, search, @context)
|
44
|
+
|
41
45
|
options.delete(:search)
|
46
|
+
options.delete(:dig)
|
47
|
+
|
42
48
|
@builder.set!(key, options, &block)
|
43
49
|
found_block, found_options = @builder.found!
|
44
50
|
@builder = prev_builder
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: props_template
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.37.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johny Ho
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date: 2024-
|
10
|
+
date: 2024-12-31 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: activesupport
|
@@ -16,40 +15,52 @@ dependencies:
|
|
16
15
|
requirements:
|
17
16
|
- - ">="
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
18
|
+
version: '7.0'
|
19
|
+
- - "<"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '9.0'
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
23
25
|
requirements:
|
24
26
|
- - ">="
|
25
27
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
28
|
+
version: '7.0'
|
29
|
+
- - "<"
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '9.0'
|
27
32
|
- !ruby/object:Gem::Dependency
|
28
33
|
name: actionview
|
29
34
|
requirement: !ruby/object:Gem::Requirement
|
30
35
|
requirements:
|
31
36
|
- - ">="
|
32
37
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
38
|
+
version: '7.0'
|
39
|
+
- - "<"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '9.0'
|
34
42
|
type: :runtime
|
35
43
|
prerelease: false
|
36
44
|
version_requirements: !ruby/object:Gem::Requirement
|
37
45
|
requirements:
|
38
46
|
- - ">="
|
39
47
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
48
|
+
version: '7.0'
|
49
|
+
- - "<"
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '9.0'
|
41
52
|
- !ruby/object:Gem::Dependency
|
42
53
|
name: oj
|
43
54
|
requirement: !ruby/object:Gem::Requirement
|
44
55
|
requirements:
|
45
|
-
- - "
|
56
|
+
- - "~>"
|
46
57
|
- !ruby/object:Gem::Version
|
47
58
|
version: '3.9'
|
48
59
|
type: :runtime
|
49
60
|
prerelease: false
|
50
61
|
version_requirements: !ruby/object:Gem::Requirement
|
51
62
|
requirements:
|
52
|
-
- - "
|
63
|
+
- - "~>"
|
53
64
|
- !ruby/object:Gem::Version
|
54
65
|
version: '3.9'
|
55
66
|
description: PropsTemplate is a direct-to-Oj, JBuilder-like DSL for building JSON.
|
@@ -80,7 +91,6 @@ homepage: https://github.com/thoughtbot/props_template/
|
|
80
91
|
licenses:
|
81
92
|
- MIT
|
82
93
|
metadata: {}
|
83
|
-
post_install_message:
|
84
94
|
rdoc_options: []
|
85
95
|
require_paths:
|
86
96
|
- lib
|
@@ -95,8 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
105
|
- !ruby/object:Gem::Version
|
96
106
|
version: '0'
|
97
107
|
requirements: []
|
98
|
-
rubygems_version: 3.
|
99
|
-
signing_key:
|
108
|
+
rubygems_version: 3.6.2
|
100
109
|
specification_version: 4
|
101
110
|
summary: A fast JSON builder
|
102
111
|
test_files: []
|