copy_tuner_client 1.4.0 → 1.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10935db209e8b915ac8101dfa324bf5a40da15978124e8300746c0be13407862
4
- data.tar.gz: faa6e39b7149540c342ec9fcefce9f0c47425614c4f361fa8b8b597ff932d69c
3
+ metadata.gz: 238593f77e71df10a71b7710228cf56cf930a320a141a74e573e9ff015b1f730
4
+ data.tar.gz: acd4453041d32c2e43b81207953fca9b68c1bbec5f4cc3dafafc4722fcaada54
5
5
  SHA512:
6
- metadata.gz: 83ea46e846b20d110366e5d8d7ecb5c415a082a700e45682931e2303a7516e50c6d1b0fcdce5ea7deada42dd3ef7e6f9df07ff4084c3b211db0cb42d1de1d422
7
- data.tar.gz: 194dc1188ab23b9776b030ec08c453444513a8f55d6b674d4b06b6953c652409951690bbfad569b1e2524a02c7951f5faeb55a4fe0d1eafbfd77c61d72cb2a45
6
+ metadata.gz: bea767cacf8232f89e3fdd6f1b6b0caee1957b7306cbf018cadfcccee49a7ce22d74640f4319771cb4dda000b61142d45190791cb46aa0b2ee4f4e1f216d7576
7
+ data.tar.gz: 8f4c0d08195e35de0918ca7b1380146770242867f681166a39d8fc206cf16965f316e532bef59baa0525fe26f069b99b876f8ba38de49f6b88d25e2d2a820edc
@@ -17,6 +17,12 @@ module CopyTunerClient
17
17
  I18n.t(key.to_s.first == '.' ? scope_key_by_partial(key) : key, **options)
18
18
  end
19
19
 
20
+ # NOTE: マーカーは HTML コメントとしてブラウザに無視されつつ Copyray オーバーレイのキー特定に
21
+ # 使われる。HTML 以外の経路(メール本文・render :json・CSV/PDF など)ではコメントが文字列として
22
+ # 出力に混入してしまうため、それらの経路には注入しない。default 引数による初期値登録は維持する
23
+ # 必要があるため、このガードは初期値登録(上の I18n.t 呼び出し)より後に置く。
24
+ return source unless copyray_injectable?
25
+
20
26
  if CopyTunerClient.configuration.disable_copyray_comment_injection
21
27
  source
22
28
  else
@@ -32,6 +38,24 @@ module CopyTunerClient
32
38
  CopyTunerClient::Copyray.augment_template(source, scope_key)
33
39
  end
34
40
  end
41
+
42
+ # NOTE: HTML 以外の経路(メール本文・render :json・CSV/PDF など)ではマーカーが文字列として
43
+ # 出力に混入するため注入しない。判定には controller.request.format を使い、@current_template.format /
44
+ # lookup_context.formats のような ActionView の内部実装には依存させない(Rails バージョン間で壊れうるため)。
45
+ def copyray_injectable?
46
+ current_controller = controller
47
+ return false if current_controller.nil?
48
+
49
+ # NOTE: mailer は request を持たず request.format で判定できない。かつメール本文への
50
+ # マーカー混入は実害が大きいため、controller の型で明示除外する。
51
+ return false if defined?(ActionMailer::Base) && current_controller.is_a?(ActionMailer::Base)
52
+
53
+ # NOTE: request が無い/format が html でない経路には注入しない。&. と || false で
54
+ # request 不在時も安全に false を返す。
55
+ current_controller.request&.format&.html? || false
56
+ end
57
+ private :copyray_injectable?
58
+
35
59
  if middleware_enabled
36
60
  alias_method :translate_without_copyray_comment, :translate
37
61
  alias_method :translate, :translate_with_copyray_comment
@@ -1,6 +1,6 @@
1
1
  module CopyTunerClient
2
2
  # Client version
3
- VERSION = '1.4.0'.freeze
3
+ VERSION = '1.5.0'.freeze
4
4
 
5
5
  # API version being used to communicate with the server
6
6
  API_VERSION = '2.0'.freeze
@@ -3,13 +3,39 @@ require 'copy_tuner_client/helper_extension'
3
3
  require 'copy_tuner_client/copyray'
4
4
 
5
5
  describe CopyTunerClient::HelperExtension do
6
+ # NOTE: helper_extension が参照する CopyTunerClient::Rails は engine への依存があり
7
+ # 単体 spec では require できないため、メソッドをスタブできる最小の入れ物だけ用意する。
8
+ module CopyTunerClient
9
+ module Rails
10
+ def self.controller_of_rails_engine?(_controller)
11
+ false
12
+ end
13
+ end
14
+ end
15
+
16
+ # NOTE: request.format で描画フォーマットを判定するため、format を差し替えられる
17
+ # 最小のフェイク request / controller を用意する。mailer 判定は controller の型で行う。
18
+ Format = Struct.new(:type) do
19
+ def html?
20
+ type == :html
21
+ end
22
+ end
23
+ Request = Struct.new(:format)
24
+ Controller = Struct.new(:request)
25
+
6
26
  module KeywordArgumentsHelper
27
+ attr_writer :controller
28
+
7
29
  def translate(key, **options)
8
30
  "Hello, #{options[:name]}"
9
31
  end
10
32
 
11
33
  def controller
12
- nil
34
+ return @controller if defined?(@controller)
35
+
36
+ # NOTE: 実 HTML 描画では controller が存在し request.format が html になるため、
37
+ # デフォルトはそれを再現した controller。
38
+ @controller = Controller.new(Request.new(Format.new(:html)))
13
39
  end
14
40
  end
15
41
 
@@ -19,14 +45,67 @@ describe CopyTunerClient::HelperExtension do
19
45
 
20
46
  CopyTunerClient::HelperExtension.hook_translation_helper(KeywordArgumentsHelper, middleware_enabled: true)
21
47
 
48
+ let(:view) { KeywordArgumentsView.new }
49
+
50
+ before do
51
+ # NOTE: controller_of_rails_engine? は ::Rails::Engine への依存があり単体 spec では評価できないため、
52
+ # この spec の関心(注入ガード)に絞って常に false を返すようスタブする。
53
+ allow(CopyTunerClient::Rails).to receive(:controller_of_rails_engine?).and_return(false)
54
+ end
55
+
22
56
  it 'works with keyword argument method' do
23
- view = KeywordArgumentsView.new
24
57
  expect(view.translate('some.key', name: 'World')).to eq '<!--COPYRAY some.key-->Hello, World'
25
58
  end
26
59
 
27
60
  it 'does not inject the overlay marker for a local_first key' do
28
61
  CopyTunerClient.configuration.local_first_key_regexp = /\Aviews\./
29
- view = KeywordArgumentsView.new
30
62
  expect(view.translate('views.foo', name: 'World')).to eq 'Hello, World'
31
63
  end
64
+
65
+ context 'injection guard by request format' do
66
+ it 'injects the marker when request.format is html' do
67
+ expect(view.translate('some.key', name: 'World')).to eq '<!--COPYRAY some.key-->Hello, World'
68
+ end
69
+
70
+ %i[json text csv pdf].each do |format|
71
+ it "does not inject the marker when request.format is :#{format}" do
72
+ view.controller = Controller.new(Request.new(Format.new(format)))
73
+ expect(view.translate('some.key', name: 'World')).to eq 'Hello, World'
74
+ end
75
+ end
76
+ end
77
+
78
+ context 'injection guard by controller' do
79
+ it 'does not inject the marker when rendered by a mailer' do
80
+ stub_const('ActionMailer::Base', Class.new)
81
+ view.controller = ActionMailer::Base.new
82
+ expect(view.translate('some.key', name: 'World')).to eq 'Hello, World'
83
+ end
84
+
85
+ it 'does not inject the marker when controller is nil' do
86
+ view.controller = nil
87
+ expect(view.translate('some.key', name: 'World')).to eq 'Hello, World'
88
+ end
89
+
90
+ it 'does not inject the marker when the controller has no request' do
91
+ view.controller = Controller.new(nil)
92
+ expect(view.translate('some.key', name: 'World')).to eq 'Hello, World'
93
+ end
94
+
95
+ it 'does not raise when ActionMailer is not loaded' do
96
+ hide_const('ActionMailer::Base') if defined?(ActionMailer::Base)
97
+ view.controller = Controller.new(Request.new(Format.new(:html)))
98
+ expect { view.translate('some.key', name: 'World') }.not_to raise_error
99
+ end
100
+ end
101
+
102
+ # NOTE: マーカー注入を抑止する非 HTML 経路でも、default 引数による初期値登録(I18n.t 呼び出し)は
103
+ # 維持されなければならない。注入ガードが初期値登録まで巻き添えで止めていないことを保証する。
104
+ context 'default value registration' do
105
+ it 'registers the default value even when the marker is not injected' do
106
+ view.controller = Controller.new(Request.new(Format.new(:json)))
107
+ expect(I18n).to receive(:t).with('some.key', hash_including(default: 'Default'))
108
+ view.translate('some.key', name: 'World', default: 'Default')
109
+ end
110
+ end
32
111
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: copy_tuner_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SonicGarden