copy_tuner_client 0.4.12 → 0.5.0.pre

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
  SHA1:
3
- metadata.gz: 065504cc3f7dfc961ad953d04a27337c74e54adb
4
- data.tar.gz: bb3a4c5e3d9b3915b7564aea2a086a353069d2de
3
+ metadata.gz: 6fe18af1c45ea03ac6fe080c00f4121c4c447db6
4
+ data.tar.gz: fa4cedc35cd14f755ec8d75fd3e2b16c2bcd7aed
5
5
  SHA512:
6
- metadata.gz: 60d5977669c7801caea1b016ac47546e2597c7c78e291b7c216d846f076c012676b2bfced6f965d5b2de62c1ede85c22253017ef6a26fc03f9df3c0cc150ca14
7
- data.tar.gz: 9cda0e40938c1e7e5b8d69ddd7791484fa9bda4b165306d270852eaf0f0d80d25e87ba5e97829cd862ad526590b364ef77ec1d996035e5a2d85de0bd9783a74b
6
+ metadata.gz: b15c3fc421a0393bb0aa7e8fd8efe71c9fe91c19b1ba8a41d479058ca044726a06d227425ce6e03997c94b9a0fc5d0d8afefe4784903649bff39cd205e48546a
7
+ data.tar.gz: 2f347762328d8d2e1dbe528508c5a86c3714c1c0cb98c3fc39c1101950758a6e5c71abca7f7c8f21c0d346715cdc5a658984e146fa99e247caaecfb29ae63ace
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.3.6
1
+ 2.4.6
data/.travis.yml CHANGED
@@ -1,19 +1,19 @@
1
1
  rvm:
2
- - 2.2
3
- - 2.3
4
- - 2.4.1
2
+ - 2.4.6
3
+ - 2.5.5
4
+ - 2.6.3
5
5
 
6
6
  gemfile:
7
- - gemfiles/4.0.gemfile
8
- - gemfiles/4.1.gemfile
9
- - gemfiles/4.2.gemfile
7
+ - gemfiles/5.0.gemfile
8
+ - gemfiles/5.1.gemfile
9
+ - gemfiles/5.2.gemfile
10
10
 
11
11
  matrix:
12
12
  exclude:
13
- - rvm: 2.4.1
14
- gemfile: gemfiles/4.0.gemfile
15
- - rvm: 2.4.1
16
- gemfile: gemfiles/4.1.gemfile
13
+ - rvm: 2.6.3
14
+ gemfile: gemfiles/5.0.gemfile
15
+ - rvm: 2.6.3
16
+ gemfile: gemfiles/5.1.gemfile
17
17
 
18
18
  before_install:
19
19
  - gem update bundler
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 0.5.0
2
+ - Not support ruby 2.3
3
+ - Add copy_tuner:detect_conflict_keys task
4
+ - Do not re-upload empty keys
5
+ - Fix dual loading tasks
6
+ - Remove config.copyray_js_injection_regexp_for_debug
7
+ - Remove config.copyray_js_injection_regexp_for_precompiled
8
+ - Download translation when initialization
9
+
1
10
  ## 0.4.11
2
11
  - changes
3
12
  - Fix hide toggle button on mobile device.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- copy_tuner_client (0.4.12)
4
+ copy_tuner_client (0.5.0.pre)
5
5
  i18n (>= 0.5.0)
6
6
  json
7
7
 
@@ -76,7 +76,7 @@ GEM
76
76
  activesupport (>= 4.1.0)
77
77
  hashdiff (0.3.2)
78
78
  i18n (0.8.1)
79
- json (2.1.0)
79
+ json (2.2.0)
80
80
  loofah (2.0.3)
81
81
  nokogiri (>= 1.5.9)
82
82
  mail (2.6.4)
data/README.md CHANGED
@@ -17,6 +17,7 @@ Create config/initializers/copy_tuner.rb
17
17
  CopyTunerClient.configure do |config|
18
18
  config.api_key = 'YOUR-API-KEY'
19
19
  config.host = 'COPY-TUNER-HOST-NAME'
20
+ config.html_escape = true
20
21
 
21
22
  # I18n keys and messages will be sent to server if the locale matches
22
23
  config.locales = [:ja, :en]
@@ -72,4 +73,3 @@ $ npm run build # Compile to a <script> containing a self-executing function
72
73
  $ bundle exec rake build # build gem to pkg/ dir
73
74
  $ bundle exec rake install # install to local gem
74
75
  $ bundle exec rake release # release gem to rubygems.org
75
-
@@ -3,6 +3,7 @@ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
3
  require 'copy_tuner_client/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
+ s.required_ruby_version = '>= 2.4.0'
6
7
  s.add_dependency 'i18n', '>= 0.5.0'
7
8
  s.add_dependency 'json'
8
9
  s.add_development_dependency 'appraisal', '~> 2.1'
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "http://rubygems.org"
4
4
 
5
- gem "rails", "4.1.16"
5
+ gem "rails", "5.0.7.2"
6
6
 
7
7
  gemspec :path => "../"
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "http://rubygems.org"
4
4
 
5
- gem "rails", "4.2.8"
5
+ gem "rails", "5.1.7"
6
6
 
7
7
  gemspec :path => "../"
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "http://rubygems.org"
4
4
 
5
- gem "rails", "4.0.13"
5
+ gem "rails", "5.2.3"
6
6
 
7
7
  gemspec :path => "../"
@@ -1,5 +1,6 @@
1
1
  require 'thread'
2
2
  require 'copy_tuner_client/client'
3
+ require 'copy_tuner_client/dotted_hash'
3
4
 
4
5
  module CopyTunerClient
5
6
  # Manages synchronization of copy between {I18nBackend} and {Client}. Acts
@@ -20,6 +21,7 @@ module CopyTunerClient
20
21
  @locales = Array(options[:locales]).map(&:to_s)
21
22
  # mutable states
22
23
  @blurbs = {}
24
+ @blank_keys = Set.new
23
25
  @queued = {}
24
26
  @started = false
25
27
  @downloaded = false
@@ -37,9 +39,12 @@ module CopyTunerClient
37
39
  # @param key [String] the key of the blurb to update
38
40
  # @param value [String] the new contents of the blurb
39
41
  def []=(key, value)
40
- return if key =~ @exclude_key_regexp
42
+ return if @exclude_key_regexp && key.match?(@exclude_key_regexp)
41
43
  return if @locales.present? && !@locales.member?(key.split('.').first)
42
- lock { @queued[key] = value }
44
+ lock do
45
+ return if @blank_keys.member?(key)
46
+ @queued[key] = value
47
+ end
43
48
  end
44
49
 
45
50
  # Keys for all blurbs stored on the server.
@@ -51,30 +56,7 @@ module CopyTunerClient
51
56
  # Yaml representation of all blurbs
52
57
  # @return [String] yaml
53
58
  def export
54
- keys = {}
55
- lock do
56
- @blurbs.sort.each do |(blurb_key, value)|
57
- current = keys
58
- yaml_keys = blurb_key.split('.')
59
-
60
- 0.upto(yaml_keys.size - 2) do |i|
61
- key = yaml_keys[i]
62
-
63
- # Overwrite en.key with en.sub.key
64
- unless current[key].class == Hash
65
- current[key] = {}
66
- end
67
-
68
- current = current[key]
69
- end
70
-
71
- current[yaml_keys.last] = value
72
- end
73
- end
74
-
75
- unless keys.size < 1
76
- keys.to_yaml
77
- end
59
+ lock { @blurbs.present? ? DottedHash.to_h(@blurbs).to_yaml : nil }
78
60
  end
79
61
 
80
62
  # Waits until the first download has finished.
@@ -108,8 +90,11 @@ module CopyTunerClient
108
90
  @started = true
109
91
 
110
92
  res = client.download do |downloaded_blurbs|
111
- downloaded_blurbs.reject! { |key, value| value == '' }
112
- lock { @blurbs = downloaded_blurbs }
93
+ blank_blurbs, blurbs = downloaded_blurbs.partition { |_key, value| value == '' }
94
+ lock do
95
+ @blank_keys = Set.new(blank_blurbs.to_h.keys)
96
+ @blurbs = blurbs.to_h
97
+ end
113
98
  end
114
99
 
115
100
  @last_downloaded_at = Time.now.utc
@@ -127,7 +112,7 @@ module CopyTunerClient
127
112
  flush
128
113
  end
129
114
 
130
- attr_reader :last_downloaded_at, :last_uploaded_at, :queued
115
+ attr_reader :last_downloaded_at, :last_uploaded_at, :queued, :blurbs
131
116
 
132
117
  def inspect
133
118
  "#<CopyTunerClient::Cache:#{object_id}>"
@@ -16,6 +16,8 @@ module CopyTunerClient
16
16
  Net::ProtocolError, SocketError, OpenSSL::SSL::SSLError,
17
17
  Errno::ECONNREFUSED]
18
18
 
19
+ USER_AGENT = "copy_tuner_client #{CopyTunerClient::VERSION}"
20
+
19
21
  # Usually instantiated from {Configuration#apply}. Copies options.
20
22
  # @param options [Hash]
21
23
  # @option options [String] :api_key API key of the project to connect to
@@ -67,7 +69,7 @@ module CopyTunerClient
67
69
  # @raise [ConnectionError] if the connection fails
68
70
  def upload(data)
69
71
  connect(host) do |http|
70
- response = http.post(uri('draft_blurbs'), data.to_json, 'Content-Type' => 'application/json')
72
+ response = http.post(uri('draft_blurbs'), data.to_json, 'Content-Type' => 'application/json', 'User-Agent' => USER_AGENT)
71
73
  check response
72
74
  log 'Uploaded missing translations'
73
75
  end
@@ -77,7 +79,7 @@ module CopyTunerClient
77
79
  # @raise [ConnectionError] if the connection fails
78
80
  def deploy
79
81
  connect(host) do |http|
80
- response = http.post(uri('deploys'), '')
82
+ response = http.post(uri('deploys'), '', 'User-Agent' => USER_AGENT)
81
83
  check response
82
84
  log 'Deployed'
83
85
  end
@@ -119,12 +119,6 @@ module CopyTunerClient
119
119
  # @return [String] The S3 host to connect to (defaults to +copy-tuner-us.s3.amazonaws.com+).
120
120
  attr_accessor :s3_host
121
121
 
122
- # @return [Regexp] Copyray js injection pattern for debug
123
- attr_accessor :copyray_js_injection_regexp_for_debug
124
-
125
- # @return [Regexp] Copyray js injection pattern for precompiled
126
- attr_accessor :copyray_js_injection_regexp_for_precompiled
127
-
128
122
  # @return [Boolean] To disable Copyray comment injection, set true
129
123
  attr_accessor :disable_copyray_comment_injection
130
124
 
@@ -136,14 +130,6 @@ module CopyTunerClient
136
130
 
137
131
  alias_method :secure?, :secure
138
132
 
139
- def copyray_js_injection_regexp_for_debug=(value)
140
- logger.warn 'DEPRECATION WARNING: copyray_js_injection_regexp_for_debug is deprecated'
141
- end
142
-
143
- def copyray_js_injection_regexp_for_precompiled=(value)
144
- logger.warn 'DEPRECATION WARNING: copyray_js_injection_regexp_for_precompiled is deprecated'
145
- end
146
-
147
133
  # Instantiated from {CopyTunerClient.configure}. Sets defaults.
148
134
  def initialize
149
135
  self.client_name = 'CopyTuner Client'
@@ -269,7 +255,7 @@ module CopyTunerClient
269
255
  process_guard.start
270
256
  end
271
257
 
272
- if test? and !disable_test_translation
258
+ if !(test? && disable_test_translation)
273
259
  logger.info "Download translation now"
274
260
  cache.download
275
261
  end
@@ -0,0 +1,32 @@
1
+ module CopyTunerClient
2
+ module DottedHash
3
+ def to_h(dotted_hash)
4
+ hash = {}
5
+ dotted_hash.to_h.transform_keys(&:to_s).sort.each do |key, value|
6
+ _hash = key.split('.').reverse.inject(value) { |memo, key| { key => memo } }
7
+ hash.deep_merge!(_hash)
8
+ end
9
+ hash
10
+ end
11
+
12
+ def conflict_keys(dotted_hash)
13
+ all_keys = dotted_hash.keys.sort
14
+ results = {}
15
+
16
+ all_keys.each_with_index do |key, index|
17
+ prefix = "#{key}."
18
+ conflict_keys = ((index + 1)..Float::INFINITY)
19
+ .take_while { |i| all_keys[i]&.start_with?(prefix) }
20
+ .map { |i| all_keys[i] }
21
+
22
+ if conflict_keys.present?
23
+ results[key] = conflict_keys
24
+ end
25
+ end
26
+
27
+ results
28
+ end
29
+
30
+ module_function :to_h, :conflict_keys
31
+ end
32
+ end
@@ -45,9 +45,5 @@ module CopyTunerClient
45
45
  initializer "copy_tuner.assets.precompile", group: :all do |app|
46
46
  app.config.assets.precompile += ["copyray.js", "copyray.css"]
47
47
  end
48
-
49
- rake_tasks do
50
- load "tasks/copy_tuner_client_tasks.rake"
51
- end
52
48
  end
53
49
  end
@@ -1,6 +1,6 @@
1
1
  module CopyTunerClient
2
2
  # Client version
3
- VERSION = '0.4.12'.freeze
3
+ VERSION = '0.5.0.pre'.freeze
4
4
 
5
5
  # API version being used to communicate with the server
6
6
  API_VERSION = '2.0'.freeze
@@ -17,4 +17,16 @@ namespace :copy_tuner do
17
17
  raise "No blurbs have been cached."
18
18
  end
19
19
  end
20
+
21
+ desc "Detect invalid keys."
22
+ task :detect_conflict_keys => :environment do
23
+ conflict_keys = CopyTunerClient::DottedHash.conflict_keys(CopyTunerClient.cache.blurbs)
24
+
25
+ if conflict_keys.empty?
26
+ puts 'All success'
27
+ else
28
+ pp conflict_keys
29
+ raise 'Exists invalid keys'
30
+ end
31
+ end
20
32
  end
@@ -95,6 +95,20 @@ describe CopyTunerClient::Cache do
95
95
  expect(cache['test.key']).to eq('test value')
96
96
  end
97
97
 
98
+ it "download included empty keys" do
99
+ client['en.test.key'] = 'test value'
100
+ client['en.test.empty'] = ''
101
+ cache = build_cache
102
+
103
+ cache.download
104
+
105
+ expect(cache['en.test.key']).to eq('test value')
106
+ expect(cache['en.test.empty']).to eq(nil)
107
+
108
+ cache['en.test.empty'] = ''
109
+ expect(cache.queued).to be_empty
110
+ end
111
+
98
112
  it "handles connection errors when flushing" do
99
113
  failure = "server is napping"
100
114
  logger = FakeLogger.new
@@ -248,65 +262,33 @@ describe CopyTunerClient::Cache do
248
262
  end
249
263
 
250
264
  describe "#export" do
251
- before do
252
- save_blurbs
253
- @cache = build_cache
254
- @cache.download
255
- end
265
+ subject { cache.export }
256
266
 
257
- let(:save_blurbs) {}
267
+ let(:cache) do
268
+ cache = build_cache
269
+ cache.download
270
+ cache
271
+ end
258
272
 
259
273
  it "can be invoked from the top-level constant" do
260
274
  CopyTunerClient.configure do |config|
261
- config.cache = @cache
275
+ config.cache = cache
262
276
  end
263
- expect(@cache).to receive(:export)
264
-
277
+ expect(cache).to receive(:export)
265
278
  CopyTunerClient.export
266
279
  end
267
280
 
268
- it "returns no yaml with no blurb keys" do
269
- expect(@cache.export).to eq(nil)
281
+ it 'returns no yaml with no blurb keys' do
282
+ is_expected.to eq nil
270
283
  end
271
284
 
272
285
  context "with single-level blurb keys" do
273
- let(:save_blurbs) do
286
+ before do
274
287
  client['key'] = 'test value'
275
288
  client['other_key'] = 'other test value'
276
289
  end
277
290
 
278
- it "returns blurbs as yaml" do
279
- exported = YAML.load(@cache.export)
280
- expect(exported['key']).to eq('test value')
281
- expect(exported['other_key']).to eq('other test value')
282
- end
283
- end
284
-
285
- context "with multi-level blurb keys" do
286
- let(:save_blurbs) do
287
- client['en.test.key'] = 'en test value'
288
- client['en.test.other_key'] = 'en other test value'
289
- client['fr.test.key'] = 'fr test value'
290
- end
291
-
292
- it "returns blurbs as yaml" do
293
- exported = YAML.load(@cache.export)
294
- expect(exported['en']['test']['key']).to eq('en test value')
295
- expect(exported['en']['test']['other_key']).to eq('en other test value')
296
- expect(exported['fr']['test']['key']).to eq('fr test value')
297
- end
298
- end
299
-
300
- context "with conflicting blurb keys" do
301
- let(:save_blurbs) do
302
- client['en.test'] = 'test value'
303
- client['en.test.key'] = 'other test value'
304
- end
305
-
306
- it "retains the new key" do
307
- exported = YAML.load(@cache.export)
308
- expect(exported['en']['test']['key']).to eq('other test value')
309
- end
291
+ it { is_expected.to eq "---\nkey: test value\nother_key: other test value\n" }
310
292
  end
311
293
  end
312
294
  end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe CopyTunerClient::DottedHash do
4
+ describe ".to_h" do
5
+ subject { CopyTunerClient::DottedHash.to_h(dotted_hash) }
6
+
7
+ context 'empty keys' do
8
+ let(:dotted_hash) { {} }
9
+
10
+ it { is_expected.to eq({}) }
11
+ end
12
+
13
+ context 'with single-level keys' do
14
+ let(:dotted_hash) { { 'key' => 'test value', other_key: 'other value' } }
15
+
16
+ it { is_expected.to eq({ 'key' => 'test value', 'other_key' => 'other value' }) }
17
+ end
18
+
19
+ context 'array of key value pairs' do
20
+ let(:dotted_hash) { [['key', 'test value'], ['other_key', 'other value']] }
21
+
22
+ it { is_expected.to eq({ 'key' => 'test value', 'other_key' => 'other value' }) }
23
+ end
24
+
25
+ context "with multi-level blurb keys" do
26
+ let(:dotted_hash) do
27
+ {
28
+ 'en.test.key' => 'en test value',
29
+ 'en.test.other_key' => 'en other test value',
30
+ 'fr.test.key' => 'fr test value',
31
+ }
32
+ end
33
+
34
+ it do
35
+ is_expected.to eq({
36
+ 'en' => {
37
+ 'test' => {
38
+ 'key' => 'en test value',
39
+ 'other_key' => 'en other test value',
40
+ },
41
+ },
42
+ 'fr' => {
43
+ 'test' => {
44
+ 'key' => 'fr test value',
45
+ },
46
+ },
47
+ })
48
+ end
49
+ end
50
+
51
+ context "with conflicting keys" do
52
+ let(:dotted_hash) do
53
+ {
54
+ 'en.test' => 'invalid value',
55
+ 'en.test.key' => 'en test value',
56
+ }
57
+ end
58
+
59
+ it { is_expected.to eq({ 'en' => { 'test' => { 'key' => 'en test value' } } }) }
60
+ end
61
+ end
62
+
63
+ describe ".conflict_keys" do
64
+ subject { CopyTunerClient::DottedHash.conflict_keys(dotted_hash) }
65
+
66
+ context 'valid keys' do
67
+ let(:dotted_hash) do
68
+ {
69
+ 'ja.hoge.test' => 'test',
70
+ 'ja.hoge.fuga' => 'test',
71
+ }
72
+ end
73
+
74
+ it { is_expected.to eq({}) }
75
+ end
76
+
77
+ context 'invalid keys' do
78
+ let(:dotted_hash) do
79
+ {
80
+ 'ja.hoge.test' => 'test',
81
+ 'ja.hoge.test.hoge' => 'test',
82
+ 'ja.hoge.test.fuga' => 'test',
83
+ 'ja.fuga.test.hoge' => 'test',
84
+ 'ja.fuga.test' => 'test',
85
+ }
86
+ end
87
+
88
+ it do
89
+ is_expected.to eq({
90
+ 'ja.fuga.test' => %w[ja.fuga.test.hoge],
91
+ 'ja.hoge.test' => %w[ja.hoge.test.fuga ja.hoge.test.hoge],
92
+ })
93
+ end
94
+ end
95
+ end
96
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: copy_tuner_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.12
4
+ version: 0.5.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - SonicGarden
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-22 00:00:00.000000000 Z
11
+ date: 2019-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -233,9 +233,9 @@ files:
233
233
  - features/step_definitions/rails_steps.rb
234
234
  - features/support/env.rb
235
235
  - features/support/rails_server.rb
236
- - gemfiles/4.0.gemfile
237
- - gemfiles/4.1.gemfile
238
- - gemfiles/4.2.gemfile
236
+ - gemfiles/5.0.gemfile
237
+ - gemfiles/5.1.gemfile
238
+ - gemfiles/5.2.gemfile
239
239
  - init.rb
240
240
  - lib/copy_tuner_client.rb
241
241
  - lib/copy_tuner_client/cache.rb
@@ -243,6 +243,7 @@ files:
243
243
  - lib/copy_tuner_client/configuration.rb
244
244
  - lib/copy_tuner_client/copyray.rb
245
245
  - lib/copy_tuner_client/copyray_middleware.rb
246
+ - lib/copy_tuner_client/dotted_hash.rb
246
247
  - lib/copy_tuner_client/engine.rb
247
248
  - lib/copy_tuner_client/errors.rb
248
249
  - lib/copy_tuner_client/i18n_backend.rb
@@ -263,6 +264,7 @@ files:
263
264
  - spec/copy_tuner_client/client_spec.rb
264
265
  - spec/copy_tuner_client/configuration_spec.rb
265
266
  - spec/copy_tuner_client/copyray_spec.rb
267
+ - spec/copy_tuner_client/dotted_hash_spec.rb
266
268
  - spec/copy_tuner_client/i18n_backend_spec.rb
267
269
  - spec/copy_tuner_client/poller_spec.rb
268
270
  - spec/copy_tuner_client/prefixed_logger_spec.rb
@@ -299,15 +301,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
299
301
  requirements:
300
302
  - - ">="
301
303
  - !ruby/object:Gem::Version
302
- version: '0'
304
+ version: 2.4.0
303
305
  required_rubygems_version: !ruby/object:Gem::Requirement
304
306
  requirements:
305
- - - ">="
307
+ - - ">"
306
308
  - !ruby/object:Gem::Version
307
- version: '0'
309
+ version: 1.3.1
308
310
  requirements: []
309
311
  rubyforge_project:
310
- rubygems_version: 2.5.2.2
312
+ rubygems_version: 2.6.14.4
311
313
  signing_key:
312
314
  specification_version: 4
313
315
  summary: Client for the CopyTuner copy management service
@@ -321,6 +323,7 @@ test_files:
321
323
  - spec/copy_tuner_client/client_spec.rb
322
324
  - spec/copy_tuner_client/configuration_spec.rb
323
325
  - spec/copy_tuner_client/copyray_spec.rb
326
+ - spec/copy_tuner_client/dotted_hash_spec.rb
324
327
  - spec/copy_tuner_client/i18n_backend_spec.rb
325
328
  - spec/copy_tuner_client/poller_spec.rb
326
329
  - spec/copy_tuner_client/prefixed_logger_spec.rb