copy_tuner_incompatible_search 1.0.0 → 2.0.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: deec2ce275a80adfa8b8cc254f8c1c231b24f105f135c9562879bc3e97594f27
4
- data.tar.gz: 3be254a36173f790085c55b5c16faf630037772adb462ea235228b63c620c628
3
+ metadata.gz: bc4286519e2113ead29b31af8cf83dfd670a7c6f6f9c6bdc64a04521761449c8
4
+ data.tar.gz: b3d299b35e57cab0718788e1835b5d9c962af93bce74949fe178b235406472d1
5
5
  SHA512:
6
- metadata.gz: f25cdab6e4336dfd507b00091758c4bdde845db9f642ea1a2ebfd80d76a421a85a6d9e6a250bfd30b48ce77ed9f909d40be257701a1f5c86134b6695a6d0c6a9
7
- data.tar.gz: d8a375d7f39a73e526c352c94acafad366bed3e74eb811be7c9685189ecec68ca58bba5f8824a2a54390d8ee4ede049e1b3da61e288359f0db0fa7212613ee06
6
+ metadata.gz: d444bc38349d99fecda3dd7f5bf6380809291f8f33b086a258ce7a32b86e454606028743763ef1f28b02cb1f822a831820e304ea3e26b928ab7a5f87aa3c4362
7
+ data.tar.gz: e251abc409a2d201075202ded4a7f1659664aa9ed37b3b9557cc79c83c891f92a0c23b2f77bae137db3150fa65348963aafab9e0be4b2c86222ee7de1fe81da8
data/.rubocop.yml CHANGED
@@ -14,3 +14,11 @@ RSpec/ReceiveMessages:
14
14
  Enabled: false
15
15
  RSpec/NestedGroups:
16
16
  Enabled: false
17
+ RSpec/ContextWording:
18
+ Enabled: false
19
+ RSpec/ExampleLength:
20
+ Enabled: false
21
+ RSpec/VerifiedDoubles:
22
+ Enabled: false
23
+ RSpec/MessageSpies:
24
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
1
  ## [Unreleased]
2
+ ## [2.0.0] - 2024-05-03
3
+
4
+ - Add command copy_tuner_incompatible_replace
5
+
2
6
  ## [1.0.0] - 2024-04-28
3
7
 
4
8
  - Release the first version
data/README.md CHANGED
@@ -20,6 +20,8 @@ If bundler is not being used to manage dependencies, install the gem by executin
20
20
 
21
21
  copy_tuner_incompatible_search
22
22
 
23
+ copy_tuner_incompatible_replace <usage.xlsx> <blurbs.csv>
24
+
23
25
  ## Development
24
26
 
25
27
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/Steepfile CHANGED
@@ -29,5 +29,7 @@
29
29
  # end
30
30
  target :lib do
31
31
  check 'lib'
32
+ # すぐにrbsを導入するのは難しそうなのであとまわし
33
+ ignore 'lib/copy_tuner_incompatible_search/replace_command.rb'
32
34
  signature 'sig'
33
35
  end
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/copy_tuner_incompatible_search'
4
+
5
+ def show_keys(keys)
6
+ if keys.empty?
7
+ puts 'なし'
8
+ else
9
+ puts keys.uniq.sort
10
+ end
11
+ puts
12
+ end
13
+
14
+ project_name = File.basename(Dir.pwd)
15
+ timestamp = Time.now.strftime('%Y%m%d%H%M%S')
16
+ output_path = "tmp/with-html-suffix-#{project_name}-#{timestamp}.csv"
17
+ usage_path = ARGV[0]
18
+ blurbs_path = ARGV[1]
19
+ if usage_path.nil? || blurbs_path.nil?
20
+ puts 'Please specify file paths: copy_tuner_incompatible_replace <usage_xlsx> <blurbs_csv>'
21
+ puts 'usage_xlsx can be created by copy_tuner_incompatible_search'
22
+ puts 'blurbs_csv can be downloaded from CopyTuner server'
23
+ exit 1
24
+ end
25
+ result = CopyTunerIncompatibleSearch::ReplaceCommand.run(usage_path, blurbs_path, output_path)
26
+
27
+ puts "非互換のキーを_html付きのキーに変換したので、#{output_path}をCopyTunerにアップロードする。コードも置換済み"
28
+ show_keys result.newly_replaced_keys
29
+
30
+ puts '非互換だが、すでに_htmlまたは.htmlつきのキーが存在していたので、コードの置換のみ実行'
31
+ show_keys result.existing_keys
32
+
33
+ puts '使用箇所を見つけられなかったキー。手動で使用箇所を特定し、手動で_html付きのキーを作成する'
34
+ show_keys result.not_used_incompatible_keys
35
+
36
+ puts '非互換のキーはconfig.ignored_keysに追加する'
37
+ show_keys result.keys_to_ignore
38
+
39
+ puts '以下のキーはすでにconfig.ignored_keysに追加済み'
40
+ show_keys result.already_ignored_keys
41
+
42
+ puts '特殊文字を含むキー。手動で使用箇所を特定し、手動で_html付きのキーを作成する。config.ignored_keys にも追加する'
43
+ show_keys result.keys_with_special_chars
44
+
45
+ puts '動的なキーが使われている箇所の数。手動で使用箇所を特定し、手動で_html付きのキーを作成する'
46
+ puts result.dynamic_count
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+ require 'set'
5
+
6
+ require 'roo'
7
+
8
+ module CopyTunerIncompatibleSearch
9
+ class ReplaceCommand # rubocop:disable Metrics/ClassLength
10
+ def self.run(usage_path, blurbs_path, output_path)
11
+ self.new(usage_path, blurbs_path).run(output_path)
12
+ end
13
+
14
+ def initialize(usage_path, blurbs_path)
15
+ @usage_path = usage_path
16
+ @blurbs_path = blurbs_path
17
+ end
18
+
19
+ def run(output_path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
20
+ # usages.xlsxから生成したUsageオブジェクトの配列
21
+ usages = usage_sheet.each(type: 'Type', key: 'Key', ignored: 'Ignored', file: 'File', line: 'Line').filter_map.with_index do |hash, i|
22
+ next if i.zero? # skip header
23
+
24
+ Usage.new(**hash)
25
+ end
26
+ # プロジェクト内で後方互換性のないキーの集合
27
+ incompatible_keys = Set[*usages.select(&:static?).map(&:key)]
28
+ # 使用箇所が判明しているUsageオブジェクトの配列(ただし、dynamicなキーを除く)
29
+ used_usages = usages.select(&:used?)
30
+ # _html付きのキーに変換する必要があるキーの集合
31
+ keys_to_convert = Set[*used_usages.map(&:key)]
32
+ # staticかつ使用箇所が判明しているUsageオブジェクトの配列を翻訳キーでグループ化
33
+ static_usages_by_key = used_usages.select(&:static?).group_by(&:key)
34
+ # lazyかつ使用箇所が判明しているUsageオブジェクトの配列を翻訳キーでグループ化
35
+ lazy_usages_by_key = used_usages.select(&:lazy?).group_by(&:key)
36
+
37
+ # blurbs.csvの全キーの集合と、特殊文字を含むキーの配列
38
+ all_blurb_keys, keys_with_special_chars = parse_blurbs_csv
39
+ # すでに_htmlで終わるキーが存在する後方互換性のないキーの集合
40
+ underscore_converted_keys = Set[*incompatible_keys.select { |k| all_blurb_keys.include?("#{k}_html") }]
41
+ # すでに.htmlで終わるキーが存在する後方互換性のないキーの集合
42
+ dot_converted_keys = Set[*incompatible_keys.select { |k| all_blurb_keys.include?("#{k}.html") }]
43
+
44
+ # コード上のキーを置換する必要があるキーの配列
45
+ keys_for_code_replace = []
46
+ # _html付きのキーを新たに登録しなければならないキーの配列
47
+ newly_replaced_keys = []
48
+ # 使用箇所が見つからなかった後方互換性のないキーの配列
49
+ not_used_incompatible_keys = []
50
+ # _html付きのキーを定義したCSVを保存する。このファイルはCopyTunerにアップロードするために使う
51
+ CSV.open(output_path, 'wb') do |csv_out|
52
+ CSV.parse(blurbs_csv_text, headers: true, quote_char: '"').each_with_index do |row, i|
53
+ if i.zero?
54
+ csv_out << row.headers
55
+ end
56
+ key = row[0]
57
+ converted_key = "#{key}_html"
58
+ if keys_to_convert.include?(key) && !dot_converted_keys.include?(key) && !underscore_converted_keys.include?(key)
59
+ csv_out << [converted_key, *row[1..]]
60
+ newly_replaced_keys << key
61
+ end
62
+ if keys_to_convert.include?(key)
63
+ keys_for_code_replace << key
64
+ elsif incompatible_keys.include?(key)
65
+ not_used_incompatible_keys << key
66
+ end
67
+ end
68
+ end
69
+
70
+ replace_code_for_static_usages(static_usages_by_key, keys_for_code_replace, underscore_converted_keys, dot_converted_keys)
71
+ replace_code_for_lazy_usages(lazy_usages_by_key, keys_for_code_replace, underscore_converted_keys, dot_converted_keys)
72
+
73
+ existing_keys = keys_for_code_replace - newly_replaced_keys
74
+ already_ignored_keys = search_ignored_keys.uniq
75
+ keys_to_ignore = usages.reject(&:dynamic?).map(&:key).uniq - already_ignored_keys
76
+ dynamic_count = usages.count(&:dynamic?)
77
+ Result.new(newly_replaced_keys, existing_keys, not_used_incompatible_keys, keys_to_ignore, already_ignored_keys, keys_with_special_chars, dynamic_count)
78
+ end
79
+
80
+ private
81
+
82
+ attr_reader :usage_path, :blurbs_path
83
+
84
+ class Usage
85
+ attr_reader :type, :key, :file, :line
86
+
87
+ def initialize(type:, key:, ignored:, file:, line:)
88
+ @type = type
89
+ @key = key
90
+ @ignored = ignored
91
+ @file = file
92
+ @line = line.to_s.empty? ? nil : line.to_i
93
+ end
94
+
95
+ def static?
96
+ @type == 'static'
97
+ end
98
+
99
+ def lazy?
100
+ @type == 'lazy'
101
+ end
102
+
103
+ def dynamic?
104
+ @type == 'dynamic'
105
+ end
106
+
107
+ def used?
108
+ !dynamic? && !@file.to_s.strip.empty?
109
+ end
110
+
111
+ def lazy_key
112
+ return unless lazy?
113
+
114
+ last_key = key.split('.').last
115
+ ".#{last_key}"
116
+ end
117
+ end
118
+
119
+ class Result
120
+ attr_reader :newly_replaced_keys, :existing_keys, :not_used_incompatible_keys, :keys_to_ignore, :already_ignored_keys, :keys_with_special_chars,
121
+ :dynamic_count
122
+
123
+ def initialize(newly_replaced_keys, existing_keys, not_used_incompatible_keys, keys_to_ignore, already_ignored_keys, keys_with_special_chars, dynamic_count) # rubocop:disable Metrics/ParameterLists, Layout/LineLength
124
+ @newly_replaced_keys = newly_replaced_keys
125
+ @existing_keys = existing_keys
126
+ @not_used_incompatible_keys = not_used_incompatible_keys
127
+ @keys_to_ignore = keys_to_ignore
128
+ @already_ignored_keys = already_ignored_keys
129
+ @keys_with_special_chars = keys_with_special_chars
130
+ @dynamic_count = dynamic_count
131
+ end
132
+ end
133
+
134
+ def usage_sheet
135
+ actual_xlsx = Roo::Spreadsheet.open(usage_path)
136
+ actual_xlsx.sheet(0)
137
+ end
138
+
139
+ def blurbs_csv_text
140
+ File.read(blurbs_path)
141
+ end
142
+
143
+ def search_ignored_keys
144
+ eval(ignored_keys_text) # rubocop:disable Security/Eval
145
+ end
146
+
147
+ def ignored_keys_text
148
+ `rails r "p CopyTunerClient::configuration.ignored_keys"`
149
+ end
150
+
151
+ def parse_blurbs_csv
152
+ keys_with_special_chars = []
153
+ all_blurb_keys = []
154
+ CSV.parse(blurbs_csv_text, headers: true, quote_char: '"').each do |row|
155
+ # FIXME: なぜか文字列で指定すると取得できない
156
+ # row['key']
157
+ key = row[0]
158
+ all_blurb_keys << key
159
+ translation = row[1]
160
+ if translation.match?(/&#\d+;|&\w+;/) && !key.match?(/[_.]html$/)
161
+ keys_with_special_chars << key
162
+ end
163
+ end
164
+ [Set[*all_blurb_keys], keys_with_special_chars]
165
+ end
166
+
167
+ def replace_code_for_lazy_usages(lazy_usages_by_key, keys_for_code_replace, underscore_converted_keys, dot_converted_keys)
168
+ lazy_usages_by_key.each do |key, usages|
169
+ next unless keys_for_code_replace.include?(key)
170
+
171
+ usages.each do |usage|
172
+ replace_code(usage, underscore_converted_keys, dot_converted_keys)
173
+ end
174
+ end
175
+ end
176
+
177
+ def replace_code_for_static_usages(static_usages_by_key, keys_for_code_replace, underscore_converted_keys, dot_converted_keys)
178
+ static_usages_by_key.each do |key, usages|
179
+ next unless keys_for_code_replace.include?(key)
180
+
181
+ usages.each do |usage|
182
+ replace_code(usage, underscore_converted_keys, dot_converted_keys)
183
+ end
184
+ end
185
+ end
186
+
187
+ def replace_code(usage, underscore_converted_keys, dot_converted_keys)
188
+ lines = file_readlines(usage.file)
189
+ if usage.lazy?
190
+ lazy_key = usage.lazy_key
191
+ regex = /(?<=['"])#{Regexp.escape(lazy_key)}(?=['"])/
192
+ else
193
+ regex = /(?<=['"])#{Regexp.escape(usage.key)}(?=['"])/
194
+ end
195
+ new_key = generate_html_key(usage, underscore_converted_keys, dot_converted_keys)
196
+ lines[usage.line - 1].gsub!(regex, new_key)
197
+ file_write(usage.file, lines.join)
198
+ end
199
+
200
+ def file_readlines(path)
201
+ File.readlines(path)
202
+ end
203
+
204
+ def file_write(path, text)
205
+ File.write(path, text)
206
+ end
207
+
208
+ # すでに_htmlまたは.htmlのキーが存在していればそのキーを、そうでなければ_html付きのキーを返す
209
+ def generate_html_key(usage, underscore_converted_keys, dot_converted_keys)
210
+ has_underscore = underscore_converted_keys.include?(usage.key)
211
+ has_dot = dot_converted_keys.include?(usage.key)
212
+ none = !has_underscore && !has_dot
213
+ key = usage.lazy? ? usage.lazy_key : usage.key
214
+ has_underscore || none ? "#{key}_html" : "#{key}.html"
215
+ end
216
+ end
217
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CopyTunerIncompatibleSearch
4
- VERSION = '1.0.0'
4
+ VERSION = '2.0.0'
5
5
  end
@@ -9,8 +9,8 @@ module CopyTunerIncompatibleSearch
9
9
  end
10
10
 
11
11
  def save_to(output_path)
12
- Axlsx::Package.new do |p|
13
- p.workbook.add_worksheet(name: 'Data') do |sheet|
12
+ Axlsx::Package.new do |pkg|
13
+ pkg.workbook.add_worksheet(name: 'Data') do |sheet|
14
14
  style = sheet.styles.add_style(font_name: 'Courier New', sz: 14)
15
15
  sheet.add_row %w[Type Key Ignored File Line Code], style: style
16
16
  sheet.auto_filter = 'A1:F1'
@@ -20,7 +20,7 @@ module CopyTunerIncompatibleSearch
20
20
  add_result_rows(sheet, result, style)
21
21
  end
22
22
  end
23
- p.serialize(output_path)
23
+ pkg.serialize(output_path)
24
24
  end
25
25
  end
26
26
 
@@ -3,6 +3,7 @@
3
3
  require_relative 'copy_tuner_incompatible_search/version'
4
4
  require_relative 'copy_tuner_incompatible_search/command'
5
5
  require_relative 'copy_tuner_incompatible_search/xlsx_writer'
6
+ require_relative 'copy_tuner_incompatible_search/replace_command'
6
7
 
7
8
  module CopyTunerIncompatibleSearch
8
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: copy_tuner_incompatible_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Junichi Ito
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-28 00:00:00.000000000 Z
11
+ date: 2024-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: caxlsx
@@ -28,6 +28,7 @@ description:
28
28
  email:
29
29
  - jit@sonicgarden.jp
30
30
  executables:
31
+ - copy_tuner_incompatible_replace
31
32
  - copy_tuner_incompatible_search
32
33
  extensions: []
33
34
  extra_rdoc_files: []
@@ -40,9 +41,11 @@ files:
40
41
  - README.md
41
42
  - Rakefile
42
43
  - Steepfile
44
+ - exe/copy_tuner_incompatible_replace
43
45
  - exe/copy_tuner_incompatible_search
44
46
  - lib/copy_tuner_incompatible_search.rb
45
47
  - lib/copy_tuner_incompatible_search/command.rb
48
+ - lib/copy_tuner_incompatible_search/replace_command.rb
46
49
  - lib/copy_tuner_incompatible_search/version.rb
47
50
  - lib/copy_tuner_incompatible_search/xlsx_writer.rb
48
51
  - sig/copy_tuner_incompatible_search.rbs