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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd81fe81e5e0d795e842a3cf75c4277d0ba5e7211214596d2755835994d27435
4
- data.tar.gz: 6a40e039b54a45ba5271525dbc27fea9294eadc7d0580e38f87c3f1d8579f6aa
3
+ metadata.gz: 159bfa45f2d0f53ef30fe11e2bd6dfbf1b07b0ea0e19530ca3ac3d171308c4ac
4
+ data.tar.gz: 15621955923af3e6aa17933faf75eb344e5be7a8bd34fe52ea526d1f88a01be3
5
5
  SHA512:
6
- metadata.gz: 6d314adee43b7c9450db5a230e6e8b3a35205ed764f102f875c9967e01205e8d19bef938715d64aa1c065f91b7cf9a7a014733e14eff6c0b711a004f58e4a363
7
- data.tar.gz: bbf37aa158dd6c518c472f7f10214648c1c6496437ba9373e14e52fe987c196d42738dc9d639c637d68c796cd6eb67e2cced94f3b5b3c755757e95accedd477d
6
+ metadata.gz: 7247f257169835737f3d834d8afc0cba5930314e439a3629acfa526b4f3d7197eece08194c3f85a848a17932a3aea22540a9386a79699d286f860c140cd8f9c7
7
+ data.tar.gz: 9416bc14041f5b8b261ecad1de0e8aa7ccaf61d3ddc11297cc6d3aa907cf14c029ae9c3e37b45d53325ed8c2bc6e87af44b580189fae59aa5f2cfb3dbddb70fc
data/README.md CHANGED
@@ -135,7 +135,7 @@ Txbr requires an Internet connection to access the Transifex and Braze APIs.
135
135
  Compatibility
136
136
  ---
137
137
 
138
- Txdb requires Ruby 2.5.
138
+ Txbr requires Ruby 2.5.
139
139
 
140
140
  Authors
141
141
  ---
@@ -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(message_id, ::Liquid::Template.parse(message))
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))
@@ -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 :liquid_template, :liquid_tag
7
+ attr_reader :template, :liquid_tag
4
8
 
5
- def initialize(liquid_template, liquid_tag)
6
- @liquid_template = liquid_template
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
- liquid_template.render
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(liquid_template.root, manifest)
28
+ extract_strings_from(template.root, manifest)
25
29
  end
26
30
  end
27
31
 
@@ -37,8 +37,7 @@ module Txbr
37
37
  def templates
38
38
  TEMPLATE_KEYS.each_with_object([]) do |name, ret|
39
39
  begin
40
- liquid_tmpl = ::Liquid::Template.parse(details[name])
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, _context = nil)
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 metadata
49
- @metadata ||= begin
50
- query_hash = CGI.parse(uri.query)
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
- private
44
+ def metadata
45
+ uri = URI.parse(url)
61
46
 
62
- def uri
63
- @uri ||= URI.parse(
64
- url.gsub(ASSIGNS_RE) do |assign|
65
- # remove curlies from beginning and end, look up in assigns hash
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
 
@@ -2,9 +2,12 @@ module Txbr
2
2
  class Template
3
3
  attr_reader :id, :liquid_template
4
4
 
5
- def initialize(id, liquid_template)
5
+ def initialize(id, source, prerender_variables = {})
6
6
  @id = id
7
- @liquid_template = liquid_template
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(liquid_template, tag)
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
@@ -1,3 +1,3 @@
1
1
  module Txbr
2
- VERSION = '2.4.1'
2
+ VERSION = '2.5.0'
3
3
  end
@@ -10,28 +10,26 @@ describe Txbr::Campaign do
10
10
 
11
11
  let(:first_message) do
12
12
  <<~MESSAGE
13
- {% assign project_slug = "my_project" %}
14
- {% assign resource_slug = "my_resource" %}
15
- {% assign translation_enabled = true %}
16
- {% connected_content http://my_strings_api.com?project_slug={{project_slug}}&resource_slug={{resource_slug}} :save strings %}
17
- {% connected_content http://my_strings_api.com?project_slug=my_project&resource_slug=my_footer_resource :save footer %}
18
-
19
- {{strings.header | default: 'Buy our stuff!'}}
20
- {% if user.gets_discount? %}
21
- {{strings.discount | default: 'You get a discount'}}
22
- {% else %}
23
- {{strings.no_discount | default: 'You get no discount'}}
24
- {% endif %}
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={{resource_slug}} :save strings %}
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('my_resource')
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('my_resource')
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(3)
110
+ expect(resources.size).to eq(2)
122
111
 
123
112
  expect(resources.first.phrases).to_not(
124
- include({ 'key' => 'meta.subject_line', 'string' => 'You lucky duck maybe' })
113
+ include({ 'key' => 'company', 'string' => 'Megamarketing Corp' })
125
114
  )
126
115
 
127
- expect(resources.last.phrases).to eq(
128
- [{ 'key' => 'meta.subject_line', 'string' => 'You lucky duck maybe' }]
116
+ expect(resources.last.phrases).to(
117
+ include({ 'key' => 'company', 'string' => 'Megamarketing Corp' })
129
118
  )
130
119
 
131
- expect(resources.first.tx_resource.project_slug).to eq('my_project')
132
- expect(resources.first.tx_resource.resource_slug).to eq('my_other_resource')
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.1
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-09-16 00:00:00.000000000 Z
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