txbr 2.4.1 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/txbr/campaign.rb +9 -1
- data/lib/txbr/content_tag.rb +9 -5
- data/lib/txbr/email_template.rb +1 -2
- data/lib/txbr/liquid/connected_content_tag.rb +12 -27
- data/lib/txbr/template.rb +30 -3
- data/lib/txbr/version.rb +1 -1
- data/spec/campaign_spec.rb +27 -32
- data/spec/template_spec.rb +27 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 159bfa45f2d0f53ef30fe11e2bd6dfbf1b07b0ea0e19530ca3ac3d171308c4ac
|
4
|
+
data.tar.gz: 15621955923af3e6aa17933faf75eb344e5be7a8bd34fe52ea526d1f88a01be3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7247f257169835737f3d834d8afc0cba5930314e439a3629acfa526b4f3d7197eece08194c3f85a848a17932a3aea22540a9386a79699d286f860c140cd8f9c7
|
7
|
+
data.tar.gz: 9416bc14041f5b8b261ecad1de0e8aa7ccaf61d3ddc11297cc6d3aa907cf14c029ae9c3e37b45d53325ed8c2bc6e87af44b580189fae59aa5f2cfb3dbddb70fc
|
data/README.md
CHANGED
data/lib/txbr/campaign.rb
CHANGED
@@ -27,6 +27,12 @@ module Txbr
|
|
27
27
|
{}
|
28
28
|
end
|
29
29
|
|
30
|
+
def prerender_variables
|
31
|
+
@prerender_variables ||= {
|
32
|
+
'campaign.${api_id}' => campaign_id
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
30
36
|
private
|
31
37
|
|
32
38
|
def template_group
|
@@ -38,7 +44,9 @@ module Txbr
|
|
38
44
|
TEMPLATE_KEYS.each_with_object([]) do |key, ret|
|
39
45
|
begin
|
40
46
|
if message = props[key]
|
41
|
-
ret << Txbr::Template.new(
|
47
|
+
ret << Txbr::Template.new(
|
48
|
+
message_id, message, prerender_variables
|
49
|
+
)
|
42
50
|
end
|
43
51
|
rescue => e
|
44
52
|
Txgh.events.publish_error!(e, metadata.merge(template_key: key))
|
data/lib/txbr/content_tag.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
require 'liquid'
|
2
|
+
require 'cgi'
|
3
|
+
require 'uri'
|
4
|
+
|
1
5
|
module Txbr
|
2
6
|
class ContentTag
|
3
|
-
attr_reader :
|
7
|
+
attr_reader :template, :liquid_tag
|
4
8
|
|
5
|
-
def initialize(
|
6
|
-
@
|
9
|
+
def initialize(template, liquid_tag)
|
10
|
+
@template = template
|
7
11
|
@liquid_tag = liquid_tag
|
8
12
|
end
|
9
13
|
|
@@ -14,14 +18,14 @@ module Txbr
|
|
14
18
|
# set local variables for the project and resource slugs. It's less
|
15
19
|
# error-prone to let Liquid do the template evaluation instead of
|
16
20
|
# grepping through the nodelist looking for assignment statements.
|
17
|
-
|
21
|
+
template.render
|
18
22
|
liquid_tag.metadata
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
22
26
|
def strings_manifest
|
23
27
|
@strings_manifest ||= StringsManifest.new.tap do |manifest|
|
24
|
-
extract_strings_from(
|
28
|
+
extract_strings_from(template.root, manifest)
|
25
29
|
end
|
26
30
|
end
|
27
31
|
|
data/lib/txbr/email_template.rb
CHANGED
@@ -37,8 +37,7 @@ module Txbr
|
|
37
37
|
def templates
|
38
38
|
TEMPLATE_KEYS.each_with_object([]) do |name, ret|
|
39
39
|
begin
|
40
|
-
|
41
|
-
ret << Txbr::Template.new(email_template_id, liquid_tmpl)
|
40
|
+
ret << Txbr::Template.new(email_template_id, details[name])
|
42
41
|
rescue => e
|
43
42
|
Txgh.events.publish_error!(e, metadata.merge(template_key: name))
|
44
43
|
end
|
@@ -23,51 +23,36 @@ module Txbr
|
|
23
23
|
# template might contain {{strings.bar}}, which would print
|
24
24
|
# out "baz".
|
25
25
|
PARSE_RE = /(:#{IDENTIFIER})\s+(#{IDENTIFIER})/
|
26
|
-
ASSIGNS_RE = /\{\{(?:(?!\}\}).)*\}\}/
|
27
26
|
|
28
27
|
attr_reader :tag_name, :url, :arguments
|
29
28
|
|
30
|
-
def initialize(tag_name, arg,
|
29
|
+
def initialize(tag_name, arg, _parse_context = nil)
|
31
30
|
@tag_name = tag_name
|
32
31
|
@url, @arguments = parse_arg(arg)
|
33
32
|
end
|
34
33
|
|
35
|
-
# this method is called inside Txbr::ContentTag#metadata
|
36
|
-
def render(context)
|
37
|
-
@metadata_hash =
|
38
|
-
Metadata::ASSIGNMENTS.each_with_object({}) do |assignment, ret|
|
39
|
-
ret[assignment] = context[assignment]
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
34
|
def prefix
|
44
35
|
# we want to blow up if "save" isn't present
|
45
36
|
arguments.fetch('save').first
|
46
37
|
end
|
47
38
|
|
48
|
-
def
|
49
|
-
@
|
50
|
-
|
51
|
-
|
52
|
-
Metadata.new(
|
53
|
-
query_hash
|
54
|
-
.each_with_object({}) { |(k, v), ret| ret[k] = v.first }
|
55
|
-
.merge('prefix' => prefix)
|
56
|
-
)
|
57
|
-
end
|
39
|
+
def render(context)
|
40
|
+
@url = ::Liquid::Template.parse(url).render(context)
|
41
|
+
''
|
58
42
|
end
|
59
43
|
|
60
|
-
|
44
|
+
def metadata
|
45
|
+
uri = URI.parse(url)
|
61
46
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
@metadata_hash[assign.gsub(/\A\{\{|\}\}\z/, '')]
|
67
|
-
end
|
47
|
+
Metadata.new(
|
48
|
+
CGI.parse(uri.query)
|
49
|
+
.each_with_object({}) { |(k, v), ret| ret[k] = v.first }
|
50
|
+
.merge('prefix' => prefix)
|
68
51
|
)
|
69
52
|
end
|
70
53
|
|
54
|
+
private
|
55
|
+
|
71
56
|
def parse_arg(arg)
|
72
57
|
url, *components = arg.split(PARSE_RE)
|
73
58
|
|
data/lib/txbr/template.rb
CHANGED
@@ -2,9 +2,12 @@ module Txbr
|
|
2
2
|
class Template
|
3
3
|
attr_reader :id, :liquid_template
|
4
4
|
|
5
|
-
def initialize(id,
|
5
|
+
def initialize(id, source, prerender_variables = {})
|
6
6
|
@id = id
|
7
|
-
|
7
|
+
|
8
|
+
@liquid_template = ::Liquid::Template.parse(
|
9
|
+
prerender(source, prerender_variables)
|
10
|
+
)
|
8
11
|
end
|
9
12
|
|
10
13
|
def each_content_tag
|
@@ -16,6 +19,14 @@ module Txbr
|
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
22
|
+
def render
|
23
|
+
liquid_template.render
|
24
|
+
end
|
25
|
+
|
26
|
+
def root
|
27
|
+
liquid_template.root
|
28
|
+
end
|
29
|
+
|
19
30
|
private
|
20
31
|
|
21
32
|
def translation_enabled?
|
@@ -39,7 +50,7 @@ module Txbr
|
|
39
50
|
|
40
51
|
def content_tags
|
41
52
|
@content_tags ||= connected_content_tags.each_with_object([]) do |tag, ret|
|
42
|
-
tag = ContentTag.new(
|
53
|
+
tag = ContentTag.new(self, tag)
|
43
54
|
ret << tag if tag.contains_translations?
|
44
55
|
end
|
45
56
|
end
|
@@ -51,5 +62,21 @@ module Txbr
|
|
51
62
|
node.is_a?(Txbr::Liquid::ConnectedContentTag)
|
52
63
|
end
|
53
64
|
end
|
65
|
+
|
66
|
+
# Designed to replace special Braze variables like {{campaign.${api_id}}},
|
67
|
+
# which Liquid can't natively handle. If the variable exists in the given
|
68
|
+
# variables hash, replace it with the value directly. Otherwise, transform
|
69
|
+
# the var into something Liquid-friendly so it doesn't jam up the parser.
|
70
|
+
def prerender(source, variables)
|
71
|
+
source.gsub(/\{\{[\w\-\.\[\]]+\.\$\{[\w\-\.\[\]]+\}\}\}/) do |orig|
|
72
|
+
orig = orig[2..-3] # remove curlies
|
73
|
+
next variables[orig] if variables.include?(orig)
|
74
|
+
"{{#{normalize_braze_var(orig)}}}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def normalize_braze_var(var)
|
79
|
+
"__braze__#{var.gsub(/[^\w\-\.\[\]]/, '')}"
|
80
|
+
end
|
54
81
|
end
|
55
82
|
end
|
data/lib/txbr/version.rb
CHANGED
data/spec/campaign_spec.rb
CHANGED
@@ -10,28 +10,26 @@ describe Txbr::Campaign do
|
|
10
10
|
|
11
11
|
let(:first_message) do
|
12
12
|
<<~MESSAGE
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
{
|
21
|
-
|
22
|
-
{
|
23
|
-
|
24
|
-
|
25
|
-
{{footer.company | default: 'Megamarketing Corp'}}
|
13
|
+
{% assign project_slug = "my_project" %}
|
14
|
+
{% assign translation_enabled = true %}
|
15
|
+
{% connected_content http://my_strings_api.com?project_slug={{project_slug}}&resource_slug={{campaign.${api_id}}} :save strings %}
|
16
|
+
{% connected_content http://my_strings_api.com?project_slug=my_project&resource_slug=my_footer_resource :save footer %}
|
17
|
+
|
18
|
+
{{strings.header | default: 'Buy our stuff!'}}
|
19
|
+
{% if user.gets_discount? %}
|
20
|
+
{{strings.discount | default: 'You get a discount'}}
|
21
|
+
{% else %}
|
22
|
+
{{strings.no_discount | default: 'You get no discount'}}
|
23
|
+
{% endif %}
|
24
|
+
{{footer.company | default: 'Megamarketing Corp'}}
|
26
25
|
MESSAGE
|
27
26
|
end
|
28
27
|
|
29
28
|
let(:second_message) do
|
30
29
|
<<~HTML
|
31
30
|
{% assign project_slug = "my_project" %}
|
32
|
-
{% assign resource_slug = "my_resource" %}
|
33
31
|
{% assign translation_enabled = true %}
|
34
|
-
{% connected_content http://my_strings_api.com?project_slug={{project_slug}}&resource_slug={{
|
32
|
+
{% connected_content http://my_strings_api.com?project_slug={{project_slug}}&resource_slug={{campaign.${api_id}}} :save strings %}
|
35
33
|
{{strings.meta.subject_line | default: 'You lucky duck maybe'}}
|
36
34
|
HTML
|
37
35
|
end
|
@@ -60,7 +58,7 @@ describe Txbr::Campaign do
|
|
60
58
|
it 'extracts and groups all strings with the same project, resource, and prefix' do
|
61
59
|
resource = campaign.each_resource.to_a.first
|
62
60
|
expect(resource.tx_resource.project_slug).to eq('my_project')
|
63
|
-
expect(resource.tx_resource.resource_slug).to eq(
|
61
|
+
expect(resource.tx_resource.resource_slug).to eq(campaign_id)
|
64
62
|
|
65
63
|
# notice how it combined strings from both messages,
|
66
64
|
expect(resource.phrases).to eq([
|
@@ -76,7 +74,7 @@ describe Txbr::Campaign do
|
|
76
74
|
tx_resource = resource.tx_resource
|
77
75
|
|
78
76
|
expect(tx_resource.project_slug).to eq('my_project')
|
79
|
-
expect(tx_resource.resource_slug).to eq(
|
77
|
+
expect(tx_resource.resource_slug).to eq(campaign_id)
|
80
78
|
expect(tx_resource.source_file).to eq('World Domination')
|
81
79
|
expect(tx_resource.source_lang).to eq(project.source_lang)
|
82
80
|
expect(tx_resource.type).to eq(project.strings_format)
|
@@ -107,29 +105,26 @@ describe Txbr::Campaign do
|
|
107
105
|
end
|
108
106
|
|
109
107
|
context 'when the message comes from a separate resource' do
|
110
|
-
let(:first_message) do
|
111
|
-
super().tap do |subj|
|
112
|
-
subj.sub!(
|
113
|
-
'resource_slug = "my_resource"',
|
114
|
-
'resource_slug = "my_other_resource"'
|
115
|
-
)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
108
|
it 'includes the additional resource' do
|
120
109
|
resources = campaign.each_resource.to_a
|
121
|
-
expect(resources.size).to eq(
|
110
|
+
expect(resources.size).to eq(2)
|
122
111
|
|
123
112
|
expect(resources.first.phrases).to_not(
|
124
|
-
include({ 'key' => '
|
113
|
+
include({ 'key' => 'company', 'string' => 'Megamarketing Corp' })
|
125
114
|
)
|
126
115
|
|
127
|
-
expect(resources.last.phrases).to
|
128
|
-
|
116
|
+
expect(resources.last.phrases).to(
|
117
|
+
include({ 'key' => 'company', 'string' => 'Megamarketing Corp' })
|
129
118
|
)
|
130
119
|
|
131
|
-
|
132
|
-
|
120
|
+
first = resources.first.tx_resource
|
121
|
+
second = resources.last.tx_resource
|
122
|
+
|
123
|
+
expect(first.project_slug).to eq('my_project')
|
124
|
+
expect(first.resource_slug).to eq(campaign_id)
|
125
|
+
|
126
|
+
expect(second.project_slug).to eq('my_project')
|
127
|
+
expect(second.resource_slug).to eq('my_footer_resource')
|
133
128
|
end
|
134
129
|
end
|
135
130
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Txbr::Template do
|
4
|
+
subject { described_class.new(id, source, prerender_variables) }
|
5
|
+
|
6
|
+
let(:prerender_variables) { {} }
|
7
|
+
let(:id) { 'foobar' }
|
8
|
+
let(:source) do
|
9
|
+
<<~SRC
|
10
|
+
<h1>Braze campaign is {{campaign.${api_id}}}</h1>
|
11
|
+
SRC
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with a direct variable replacement' do
|
15
|
+
let(:prerender_variables) { { 'campaign.${api_id}' => 'abc123' } }
|
16
|
+
|
17
|
+
it 'prerenders correctly' do
|
18
|
+
expect(subject.render.strip).to eq("<h1>Braze campaign is abc123</h1>")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with no variable replacements' do
|
23
|
+
it 'renders without erroring' do
|
24
|
+
expect { subject.render }.to_not raise_error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: txbr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cameron Dutro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: abroad
|
@@ -155,6 +155,7 @@ files:
|
|
155
155
|
- spec/support/fake_connection.rb
|
156
156
|
- spec/support/standard_setup.rb
|
157
157
|
- spec/support/test_config.rb
|
158
|
+
- spec/template_spec.rb
|
158
159
|
- spec/uploader_spec.rb
|
159
160
|
- spec/utils_spec.rb
|
160
161
|
- txbr.gemspec
|