anpo 0.1.0 → 1.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: fdf7af205951539c90a16f0cec615f1acfc247c8a573ed5e65fbb904cecd1470
4
- data.tar.gz: a07c13bf87ed7199242ee4b6bafc4144dbe8f87a13e95e956900f1fa2c62def4
3
+ metadata.gz: b86255b8dcc794f8aa38dbd06a8b24840baae8308192061673a1b4c024d2887d
4
+ data.tar.gz: 91ae182af6f1f8f398b0ee0c61821ebd829398f486f3001ef10c9f4197c74aa8
5
5
  SHA512:
6
- metadata.gz: 0b4fe961b9a28bbcbe6353939b0bd5a4ead8e06cbf90720c949971c0cdfb93383808b675a4d3ad29cf6364ec0bb83655a6c76e963efba838176d95c7cf11f6ed
7
- data.tar.gz: 2fe2ae8f06f395272eb715993a3fcbb7d3d942ed88270117f4d25e81adc282b90a26cc19a5d8b86079235bd2b61c3ad6cb33f04e07b5d56253e358cccf1e7833
6
+ metadata.gz: cfce5c4b50344e28e1ba6a86226206bd1c6c7a80bca17bc45ac42a4cd776db882dc63dc5d09278bf76f5871abb9529734f8da50b2e67e8c65e21845c6157905d
7
+ data.tar.gz: aaf924b90685cad5da37f685426548bdd254f6cd13e89ae91c5f943fe7e77ad85cafa6f70adddbbbdb6fc862e798663f9d7e8317e42db2f2cc48d1171d3f9589
data/Rakefile CHANGED
@@ -2,7 +2,10 @@
2
2
 
3
3
  require "bundler/gem_tasks"
4
4
  require "rubocop/rake_task"
5
+ require "rspec/core/rake_task"
5
6
 
6
7
  RuboCop::RakeTask.new
7
8
 
8
- task default: :rubocop
9
+ RSpec::Core::RakeTask.new("spec")
10
+
11
+ task default: :spec
data/anpo.gemspec CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
16
16
 
17
- #spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
17
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
18
18
 
19
19
  spec.metadata["homepage_uri"] = spec.homepage
20
20
  spec.metadata["source_code_uri"] = "https://github.com/soburi/anpo"
@@ -29,8 +29,9 @@ Gem::Specification.new do |spec|
29
29
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
30
  spec.require_paths = ["lib"]
31
31
 
32
- # Uncomment to register a new dependency of your gem
33
- # spec.add_dependency "example-gem", "~> 1.0"
32
+ spec.add_development_dependency "bundler", "~> 2.0"
33
+ spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "rspec", "~> 3.0"
34
35
 
35
36
  # For more information and examples about making a new gem, checkout our
36
37
  # guide at: https://bundler.io/guides/creating_gem.html
data/bin/anpofilter ADDED
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "anpo"
5
+ require "optparse"
6
+
7
+ def ep(x)
8
+ $stderr.print(x.inspect)
9
+ $stderr.print("\n")
10
+ end
11
+
12
+ opt = OptionParser.new
13
+
14
+ exclude_not_fuzzy = false
15
+ exclude_not_translated = false
16
+ exclude_translated = false
17
+ exclude_fuzzy = false
18
+ matchstr = false
19
+
20
+ subtract = false
21
+ intersect = false
22
+
23
+ argfile = nil
24
+
25
+ opt.on("--str") { matchstr = true }
26
+
27
+ opt.on("--intersect") { |_f| intersect = true }
28
+ opt.on("--and") { |_f| intersect = true }
29
+ opt.on("-A") { |_f| intersect = true }
30
+ opt.on("--subtract") { |_f| subtract = true }
31
+ opt.on("-S") { |_f| subtract = true }
32
+
33
+ opt.on("-f") { |_x| exclude_not_fuzzy = true }
34
+ opt.on("-F") { |_x| exclude_fuzzy = true }
35
+ opt.on("-t") { |_x| exclude_not_translated = true }
36
+ opt.on("-T") { |_x| exclude_translated = true }
37
+
38
+ argv = opt.parse!(ARGV)
39
+
40
+ if intersect || subtract
41
+
42
+ inputs = []
43
+ inputs = if argv.length == 1
44
+ [argv[0], $stdin]
45
+ else
46
+ [argv[1], argv[0]]
47
+ end
48
+
49
+ File.open(inputs[0]) do |file|
50
+ Anpo::PO.parse(file) do |cmpfile|
51
+ infile = Anpo::PO.parse(inputs[1])
52
+
53
+ cmpfile.entries.delete_if(&:is_fuzzy?) if exclude_fuzzy
54
+ cmpfile.entries.delete_if { |e| !e.is_translated? } if exclude_not_translated
55
+
56
+ ids = []
57
+ infile.each do |ent|
58
+ ids.push(ent.msgid) if !cmpfile.msg[ent.msgid] || ((cmpfile.msg[ent.msgid] != ent.msgstr) && matchstr)
59
+ end
60
+
61
+ if subtract
62
+ infile.filter_by_ids(ids)
63
+ elsif intersect
64
+ infile.delete_by_ids(ids)
65
+ end
66
+
67
+ print infile
68
+ end
69
+ end
70
+
71
+ else
72
+
73
+ Anpo::PO.parse(argv.empty? ? $stdin : ARGV[0]) do |po|
74
+ po.entries.delete_if { |e| !e.is_fuzzy? } if exclude_not_fuzzy
75
+ po.entries.delete_if(&:is_fuzzy?) if exclude_fuzzy
76
+ po.entries.delete_if { |e| !e.is_translated? } if exclude_translated
77
+ po.entries.delete_if(&:is_translated?) if exclude_not_translated
78
+ print po
79
+ end
80
+
81
+ end
data/lib/anpo.rb CHANGED
@@ -1,37 +1,63 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "anpo/version"
4
+ require "csv"
5
+ require "stringio"
4
6
 
5
7
  module Anpo
6
8
  class Error < StandardError; end
7
9
 
8
10
  class POEntry
9
- attr_accessor :msgid
10
- attr_accessor :msgstr
11
11
  attr_accessor :comments
12
- attr_accessor :is_header
13
12
 
14
- def initialize(lines, header=false)
15
- state = ''
16
- @is_header = header
13
+ def on_changed(&proc)
14
+ @change_listener.push(proc)
15
+ end
16
+
17
+ def msgid
18
+ @msgid.clone
19
+ end
20
+
21
+ def msgid=(id)
22
+ @change_listener.each do |prc|
23
+ prc.call(self, id, @msgstr)
24
+ end
25
+ @msgid = id
26
+ end
27
+
28
+ def msgstr
29
+ @msgstr.clone
30
+ end
31
+
32
+ def msgstr=(str)
33
+ @change_listener.each do |prc|
34
+ prc.call(self, @msgid, str)
35
+ end
36
+ @msgstr = str
37
+ end
38
+
39
+ def initialize(lines = nil)
40
+ state = ""
41
+ @change_listener = []
17
42
  @msgid = nil
18
43
  @msgstr = nil
19
44
  @comments = []
20
- lines.each do |l|
21
- if l.start_with?("msgid")
22
- state = "msgid"
23
- @msgid = l.gsub("msgid \"","").gsub(/\"\s*$/,"")
24
- elsif l.start_with?("msgstr")
25
- state = "msgstr"
26
- @msgstr = l.gsub("msgstr \"","").gsub(/\"\s*$/,"")
27
- elsif l.start_with?("#")
28
- state = "comment"
29
- @comments.push(l.gsub("\n",'') )
30
- else
31
- if state == "msgid"
32
- @msgid = @msgid + "\n" + l.gsub(/^\s*\"/,'').gsub(/\"\s*$/,'')
45
+
46
+ unless lines.nil?
47
+ lines.each do |l|
48
+ if l.start_with?("msgid")
49
+ state = "msgid"
50
+ @msgid = l.gsub("msgid \"", "").gsub(/"\s*$/, "")
51
+ elsif l.start_with?("msgstr")
52
+ state = "msgstr"
53
+ @msgstr = l.gsub("msgstr \"", "").gsub(/"\s*$/, "")
54
+ elsif l.start_with?("#")
55
+ state = "comment"
56
+ @comments.push(l.gsub("\n", ""))
57
+ elsif state == "msgid"
58
+ @msgid = @msgid + "\n" + l.gsub(/^\s*"/, "").gsub(/"\s*$/, "")
33
59
  elsif state == "msgstr"
34
- @msgstr = @msgstr + "\n" + l.gsub(/^\s*\"/,'').gsub(/\"\s*$/,'')
60
+ @msgstr = @msgstr + "\n" + l.gsub(/^\s*"/, "").gsub(/"\s*$/, "")
35
61
  end
36
62
  end
37
63
  end
@@ -42,26 +68,30 @@ module Anpo
42
68
  end
43
69
 
44
70
  def is_translated?
45
- @msgstr.empty? and not @msgid.empty?
71
+ (@msgid and !@msgid.empty?) and (@msgstr and !@msgstr.empty?)
72
+ end
73
+
74
+ def is_header?
75
+ @msgid and @msgid.empty? and !@msgstr.empty?
46
76
  end
47
77
 
48
78
  def msgid_to_s
49
- if @msgid == nil and @is_header
50
- "msgid \"\"\n"
51
- elsif @msgid == nil
79
+ if @msgid.nil?
52
80
  ""
81
+ elsif is_header?
82
+ "msgid \"\"\n"
53
83
  else
54
- "msgid " + @msgid.split("\n").collect{|x| "\"#{x}\""}.join("\n") + "\n"
84
+ "msgid " + @msgid.split("\n").collect { |x| "\"#{x}\"" }.join("\n") + "\n"
55
85
  end
56
86
  end
57
87
 
58
88
  def msgstr_to_s
59
- if @msgid == nil and not @is_header
89
+ if @msgid.nil?
60
90
  ""
61
91
  elsif @msgstr.empty?
62
92
  "msgstr \"\"\n"
63
93
  else
64
- "msgstr " + @msgstr.split("\n").collect{|x| "\"#{x}\""}.join("\n") + "\n"
94
+ "msgstr " + @msgstr.split("\n").collect { |x| "\"#{x}\"" }.join("\n") + "\n"
65
95
  end
66
96
  end
67
97
 
@@ -74,126 +104,285 @@ module Anpo
74
104
  end
75
105
 
76
106
  def to_s
77
- comments_to_s + msgid_to_s + msgstr_to_s
107
+ comments_to_s + msgid_to_s + msgstr_to_s
78
108
  end
79
109
  end
80
110
 
81
- class PO
82
-
83
- include Enumerable
111
+ class PO < Array
112
+ private
84
113
 
85
- def self.parse(file, &block)
86
- pofile = PO.new(file)
87
- if block
88
- block.call(pofile)
89
- else
90
- pofile
114
+ def set_on_changed(entry)
115
+ entry.on_changed do |_e, _newid, _newstr|
116
+ @dirty = true
91
117
  end
92
118
  end
93
119
 
94
- attr_accessor :entries
120
+ public
95
121
 
96
- def [](key)
97
- @hcache[key]
122
+ def <<(*args)
123
+ super
124
+ @dirty = true
98
125
  end
99
126
 
100
- def update_hashcache
101
- @hcache = {}
102
- @entries.each do |e|
103
- @hcache[e.msgid] = e.msgstr
104
- end
127
+ def append(*args)
128
+ super
129
+ @dirty = true
105
130
  end
106
131
 
107
- def entry(id)
108
- @entries.find {|e| e.msgid == id}
132
+ def clear(*args)
133
+ super
134
+ @dirty = true
109
135
  end
110
136
 
111
- def each(&block)
112
- @entries.each do |e|
113
- block.call(e)
114
- end
137
+ def collect!(*args)
138
+ super
139
+ @dirty = true
140
+ end
141
+
142
+ def compact!(*args)
143
+ super
144
+ @dirty = true
145
+ end
146
+
147
+ def concat(*args)
148
+ super
149
+ @dirty = true
150
+ end
151
+
152
+ def delete(*args)
153
+ super
154
+ @dirty = true
155
+ end
156
+
157
+ def delete_at(*args)
158
+ super
159
+ @dirty = true
160
+ end
161
+
162
+ def delete_if(*args)
163
+ super
164
+ @dirty = true
165
+ end
166
+
167
+ def fill(*args)
168
+ super
169
+ @dirty = true
170
+ end
171
+
172
+ def filter!(*args)
173
+ super
174
+ @dirty = true
175
+ end
176
+
177
+ def flatten!(*args)
178
+ super
179
+ @dirty = true
180
+ end
181
+
182
+ def insert(*args)
183
+ super
184
+ @dirty = true
185
+ end
186
+
187
+ def keep_if(*args)
188
+ super
189
+ @dirty = true
190
+ end
191
+
192
+ def map!(*args)
193
+ super
194
+ @dirty = true
195
+ end
196
+
197
+ def pop(*args)
198
+ super
199
+ @dirty = true
200
+ end
201
+
202
+ def prepend(*args)
203
+ super
204
+ @dirty = true
205
+ end
206
+
207
+ def push(*args)
208
+ super
209
+ @dirty = true
210
+ end
211
+
212
+ def reject!(*args)
213
+ super
214
+ @dirty = true
215
+ end
216
+
217
+ def replace(*args)
218
+ super
219
+ @dirty = true
220
+ end
221
+
222
+ def reverse!(*args)
223
+ super
224
+ @dirty = true
225
+ end
226
+
227
+ def rotate!(*args)
228
+ super
229
+ @dirty = true
230
+ end
231
+
232
+ def select!(*args)
233
+ super
234
+ @dirty = true
115
235
  end
116
236
 
117
- def keys()
118
- @hcache.keys
237
+ def shift(*args)
238
+ super
239
+ @dirty = true
119
240
  end
120
241
 
121
- def values()
122
- @hcache.values
242
+ def shuffle!(*args)
243
+ super
244
+ @dirty = true
123
245
  end
124
246
 
125
- def filter_by_ids(ids)
126
- filterids = @entries.collect {|e| e.msgid}
247
+ def slice!(*args)
248
+ super
249
+ @dirty = true
250
+ end
251
+
252
+ def sort!(*args)
253
+ super
254
+ @dirty = true
255
+ end
256
+
257
+ def sort_by!(*args)
258
+ super
259
+ @dirty = true
260
+ end
261
+
262
+ def uniq!(*args)
263
+ super
264
+ @dirty = true
265
+ end
127
266
 
128
- if not (ids - filterids).empty?
129
- raise
267
+ def unshift(*args)
268
+ super
269
+ @dirty = true
270
+ end
271
+
272
+ def msg
273
+ if @dirty
274
+ @msg.clear
275
+ each do |e|
276
+ @msg[e.msgid] = e.msgstr
277
+ end
278
+ @dirty = false
279
+ end
280
+ @msg
281
+ end
282
+
283
+ def self.parse(input, mode = "r", _opt = {}, &block)
284
+ po = nil
285
+ if input.is_a?(IO)
286
+ po = PO.new(input)
287
+ elsif FileTest.exists?(input.to_s)
288
+ File.open(input.to_s, mode) do |f|
289
+ po = PO.new(f)
290
+ end
130
291
  end
131
292
 
132
- filterids = filterids - ids
133
- @entries.delete_if {|e| filterids.include?(e.msgid)}
134
- update_hashcache
293
+ if block
294
+ block.call(po)
295
+ nil
296
+ else
297
+ po
298
+ end
299
+ end
300
+
301
+ def entry(id)
302
+ find { |e| e.msgid == id }
303
+ end
304
+
305
+ def new_entry(msgid, msgstr, comments = nil)
306
+ poe = POEntry.new
307
+ set_on_changed(poe)
308
+ poe.msgid = msgid
309
+ poe.msgstr = msgstr
310
+ poe.comments = comments || []
311
+ push(poe)
312
+ end
313
+
314
+ def filter_by_ids(keepids, _force = false)
315
+ ids = collect { |e| e.msgid }
316
+
317
+ raise unless (keepids - ids).empty?
318
+
319
+ keep_if { |e| keepids.include?(e.msgid) }
135
320
  end
136
321
 
137
322
  def delete_by_ids(deleteids)
138
- ids = @entries.collect {|e| e.msgid}
323
+ ids = collect { |e| e.msgid }
139
324
 
140
- if not (deleteids - ids).empty?
141
- raise
142
- end
325
+ raise unless (deleteids - ids).empty?
143
326
 
144
- @entries.delete_if {|e| deleteids.include?(e.msgid)}
145
- update_hashcache
327
+ delete_if { |e| deleteids.include?(e.msgid) }
146
328
  end
147
329
 
148
- def initialize(file)
330
+ def initialize(io = nil)
331
+ super()
149
332
  @caches = []
150
- @entries = []
151
333
  @header = nil
334
+ @msg = {}
152
335
 
153
- buffer = []
336
+ if io
337
+ _self = self
338
+ proc_new_entry = proc do |buf|
339
+ ent = POEntry.new(buf)
340
+ set_on_changed(ent)
154
341
 
155
- while l = file.gets
156
- if not @header
157
- if l == "\n"
158
- @header = POEntry.new(buffer, true)
159
- buffer = []
342
+ if ent.is_header?
343
+ if @header
344
+ STDERR.print("duplicate header\n" + ent.to_s)
345
+ else
346
+ @header = ent
347
+ end
348
+ elsif ent.msgid.nil?
349
+ @caches.push(ent)
160
350
  else
161
- buffer.push(l)
351
+ push(ent)
162
352
  end
163
- next
164
353
  end
165
354
 
166
- if l == "\n"
167
- ent = POEntry.new(buffer)
168
- if ent.msgid == nil
169
- @caches.push(ent)
355
+ buffer = []
356
+ while (l = io.gets)
357
+ if l == "\n"
358
+ proc_new_entry.call(buffer)
359
+ buffer = []
170
360
  else
171
- if ent.msgid != nil and ent.msgid.empty?
172
- STDERR.print("duplicate header\n" + ent.to_s)
173
- else
174
- @entries.push(ent)
175
- end
361
+ buffer.push(l)
176
362
  end
177
- buffer = []
178
- else
179
- buffer.push(l)
180
363
  end
181
- end
182
- ent = POEntry.new(buffer)
183
- if ent.msgid == nil
184
- @caches.push(ent)
364
+
365
+ proc_new_entry.call(buffer)
185
366
  else
186
- if not (ent.msgid != nil and ent.msgid.empty?)
187
- @entries.push(ent)
188
- end
367
+ @header = POEntry.new
368
+ set_on_changed(@header)
369
+ @header.msgid = ""
370
+ @header.msgstr = "\n"
189
371
  end
190
- update_hashcache
191
- self
192
372
  end
193
373
 
194
- def to_s(with_cache=true)
195
- ([@header] + @entries + (with_cache ? @caches : [])).collect{|e| e.to_s}.join("\n").to_s
374
+ def to_s(with_cache = true)
375
+ ([@header] + self + (with_cache ? @caches : [])).collect { |e| e.to_s }.join("\n").to_s
196
376
  end
197
377
 
378
+ def to_csv(opts = {})
379
+ # CSV.new(StringIO.new, opts)
380
+ csvstr = CSV.generate(opts) do |csv|
381
+ ([@header] + self + @caches).each do |e|
382
+ csv << [e.comments_to_s.chop, e.msgid, e.msgstr]
383
+ end
384
+ end
385
+ CSV.new(StringIO.new(csvstr))
386
+ end
198
387
  end
199
388
  end
data/lib/anpo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Anpo
4
- VERSION = "0.1.0"
4
+ VERSION = "1.0.0"
5
5
  end
metadata CHANGED
@@ -1,15 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anpo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - TOKITA, Hiroshi
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-13 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-03-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
13
55
  description: Simple and stupidly pofile parser.
14
56
  email:
15
57
  - tokita.hiroshi@gmail.com
@@ -27,6 +69,7 @@ files:
27
69
  - README.md
28
70
  - Rakefile
29
71
  - anpo.gemspec
72
+ - bin/anpofilter
30
73
  - bin/console
31
74
  - bin/setup
32
75
  - lib/anpo.rb
@@ -38,7 +81,7 @@ metadata:
38
81
  homepage_uri: https://github.com/soburi/anpo
39
82
  source_code_uri: https://github.com/soburi/anpo
40
83
  changelog_uri: https://github.com/soburi/anpo/CHANGELOG.md
41
- post_install_message:
84
+ post_install_message:
42
85
  rdoc_options: []
43
86
  require_paths:
44
87
  - lib
@@ -53,8 +96,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
96
  - !ruby/object:Gem::Version
54
97
  version: '0'
55
98
  requirements: []
56
- rubygems_version: 3.2.9
57
- signing_key:
99
+ rubygems_version: 3.2.3
100
+ signing_key:
58
101
  specification_version: 4
59
102
  summary: A nutty pofile parser
60
103
  test_files: []