text_alignment 0.5 → 0.6.2

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: 9f5f7f27c8628123530d51d0a68060aa6fb850bcef8c7089c8bf990f7257a80b
4
- data.tar.gz: 45f768df4e7d89c931295985adb31df9e725156e5a85d7f78a5b7cd26d00be4d
3
+ metadata.gz: c4b2cdf0c257b74c6bec90b93d1907787f3c102108046731c2755684a1b156e9
4
+ data.tar.gz: 85334dad09a046432503183e3d3ad83841612299038f2f2dac1f9d5d208e1939
5
5
  SHA512:
6
- metadata.gz: 4004293fa10eb247110764d16a24900a10e714072227dd6e5626d2123deca4bcec00b7255e1affaba4d7dda75d7e42049aabf6b1e6c51f4c005124443b5f9ffc
7
- data.tar.gz: eb5c8a2c89c8973242bb77457e0f8d9922486d9743e7c39ee12ea4025ece6d888be5308eaddec076e5a21c84149dcb31bc0ed6fcd68881fb6c8c4063e49fb64d
6
+ metadata.gz: 9272bdd6c56717b53d39b3f2009259accb608ea86b99758b6a7ee9cee1e7b275330db55af4e0eba1eba80ee69275a21a3179243394d24139b3018996f659abe1
7
+ data.tar.gz: a6a9d97d2bf81ac0c2972fd6e9d5202116156d8ff2e5e81a9bf0306e313dbc601522f887bcbcebff8b9d888cc06826a8ce69ba908dce29fa8decad85d53008af
@@ -35,6 +35,10 @@ def align_mdoc(source_annotations, target_annotations)
35
35
  source_annotations.each do |annotations|
36
36
  alignment = TextAlignment::TextAlignment.new(annotations[:text], target_annotations[:text])
37
37
 
38
+ puts alignment.alignment_show
39
+ puts "-----"
40
+ puts
41
+
38
42
  # alignment.block_alignments.each do |a|
39
43
  # p {source:a[:source], target:a[:target]}
40
44
  # puts "--"
@@ -133,26 +137,26 @@ else
133
137
 
134
138
  source_text = source_annotations[:text]
135
139
 
136
- # puts "[block alignment]"
137
- puts alignment.alignment_table
138
- # puts "====="
140
+ puts "[block alignment]"
141
+ puts alignment.alignment_show
142
+ puts "====="
139
143
  # exit
140
144
 
141
145
  # verification of source denotations
142
- # puts "[Invalid source denotations]"
143
- # source_annotations[:denotations] do |d|
144
- # p d unless d[:span][:begin] && d[:span][:end] && d[:span][:begin] < d[:span][:end] && d[:span][:begin] >= 0 && d[:span][:end] < source_text.length
145
- # end
146
- # puts "====="
147
- # puts
146
+ puts "[Invalid source denotations]"
147
+ source_annotations[:denotations] do |d|
148
+ p d unless d[:span][:begin] && d[:span][:end] && d[:span][:begin] < d[:span][:end] && d[:span][:begin] >= 0 && d[:span][:end] < source_text.length
149
+ end
150
+ puts "====="
151
+ puts
148
152
 
149
153
  denotations = alignment.transform_hdenotations(source_annotations[:denotations])
150
- # puts "[Invalid transformation]"
151
- # denotations.each do |d|
152
- # p d unless d[:span][:begin] && d[:span][:end] && d[:span][:begin] < d[:span][:end] && d[:span][:begin] >= 0 && d[:span][:end] < target_text.length
153
- # end
154
- # puts "====="
155
- # puts
154
+ puts "[Invalid transformation]"
155
+ denotations.each do |d|
156
+ p d unless d[:span][:begin] && d[:span][:end] && d[:span][:begin] < d[:span][:end] && d[:span][:begin] >= 0 && d[:span][:end] < target_text.length
157
+ end
158
+ puts "====="
159
+ puts
156
160
 
157
161
  lost_annotations += alignment.lost_annotations if alignment.lost_annotations
158
162
 
@@ -33,7 +33,9 @@ class TextAlignment::LCSComparison
33
33
  @str2_match_initial = sdiff[match_initial].new_position
34
34
  @str1_match_final = sdiff[match_final].old_position
35
35
  @str2_match_final = sdiff[match_final].new_position
36
- @similarity = 2 * lcs / ((@str1_match_final - @str1_match_initial + 1) + (@str2_match_final - @str2_match_initial + 1)).to_f
36
+ mlcs = sdiff.count{|d| d.action == '=' && d.old_element =~ /\S/ && d.new_element =~ /\S/}
37
+ @similarity = 2 * mlcs / (str1[@str1_match_initial .. @str1_match_final].scan(/\S/).count + str2[@str2_match_initial .. @str2_match_final].scan(/\S/).count).to_f
38
+ # @similarity = 2 * lcs / (str1[@str1_match_initial .. @str1_match_final].length + str2[@str2_match_initial .. @str2_match_final].length).to_f
37
39
  else
38
40
  @str1_match_initial = 0
39
41
  @str2_match_initial = 0
@@ -8,30 +8,29 @@ module TextAlignment; end unless defined? TextAlignment
8
8
  TextAlignment::PADDING_LETTERS = ['@', '^', '|', '#', '$', '%', '&', '_'] unless defined? TextAlignment::PADDING_LETTERS
9
9
 
10
10
  class TextAlignment::TextAlignment
11
- attr_reader :block_alignments
11
+ attr_reader :block_alignment
12
12
  attr_reader :similarity
13
13
  attr_reader :lost_annotations
14
14
 
15
15
  def initialize(_str1, _str2, _size_ngram = nil, _size_window = nil, _text_similiarity_threshold = nil)
16
16
  raise ArgumentError, "nil string" if _str1.nil? || _str2.nil?
17
17
 
18
- @ostr1 = _str1
19
- @ostr2 = _str2
18
+ @block_alignment = {source_text:_str1, target_text:_str2}
20
19
 
21
20
  str1, str2, mappings = string_preprocessing(_str1, _str2)
22
21
 
23
22
  # try exact match
24
23
  block_begin = str2.index(str1)
25
24
  unless block_begin.nil?
26
- @block_alignments = [{source:{begin:0, end:str1.length}, target:{begin:block_begin, end:block_begin + str1.length}, delta:block_begin}]
27
- return @block_alignments
25
+ @block_alignment[:blocks] = [{source:{begin:0, end:str1.length}, target:{begin:block_begin, end:block_begin + str1.length}, delta:block_begin, alignment: :block}]
26
+ return @block_alignment
28
27
  end
29
28
 
30
29
  # try exact match
31
30
  block_begin = str2.downcase.index(str1.downcase)
32
31
  unless block_begin.nil?
33
- @block_alignments = [{source:{begin:0, end:str1.length}, target:{begin:block_begin, end:block_begin + str1.length}, delta:block_begin}]
34
- return @block_alignments
32
+ @block_alignment[:blocks] = [{source:{begin:0, end:str1.length}, target:{begin:block_begin, end:block_begin + str1.length}, delta:block_begin, alignment: :block}]
33
+ return @block_alignment
35
34
  end
36
35
 
37
36
  anchor_finder = TextAlignment::AnchorFinder.new(str1, str2, _size_ngram, _size_window, _text_similiarity_threshold)
@@ -64,7 +63,7 @@ class TextAlignment::TextAlignment
64
63
  # puts
65
64
 
66
65
  ## To find block alignments
67
- @block_alignments = []
66
+ @block_alignment[:blocks] = []
68
67
  return if mblocks.empty?
69
68
 
70
69
  # Initial step
@@ -73,35 +72,36 @@ class TextAlignment::TextAlignment
73
72
  e2 = mblocks[0][:target][:begin]
74
73
 
75
74
  if mblocks[0][:target][:begin] == 0
76
- @block_alignments << {source:{begin:0, end:e1}, target:{begin:0, end:0}, alignment: :empty}
75
+ @block_alignment[:blocks] << {source:{begin:0, end:e1}, target:{begin:0, end:0}, alignment: :empty}
77
76
  else
78
77
  _str1 = str1[0 ... e1]
79
78
  _str2 = str2[0 ... e2]
80
79
 
81
80
  unless _str1.strip.empty?
82
81
  if _str2.strip.empty?
83
- @block_alignments << {source:{begin:0, end:e1}, target:{begin:0, end:e2}, alignment: :empty}
82
+ @block_alignment[:blocks] << {source:{begin:0, end:e1}, target:{begin:0, end:e2}, alignment: :empty}
84
83
  else
85
84
  len_min = [_str1.length, _str2.length].min
86
85
  len_buffer = (len_min * (1 + TextAlignment::BUFFER_RATE)).to_i + TextAlignment::BUFFER_MIN
87
86
  b1 = _str1.length < len_buffer ? 0 : e1 - len_buffer
88
87
  b2 = _str2.length < len_buffer ? 0 : e2 - len_buffer
89
88
 
90
- @block_alignments << {source:{begin:0, end:b1}, target:{begin:0, end:b2}, alignment: :empty} if b1 > 0
89
+ @block_alignment[:blocks] << {source:{begin:0, end:b1}, target:{begin:0, end:b2}, alignment: :empty} if b1 > 0
91
90
 
92
91
  _str1 = str1[b1 ... e1]
93
92
  _str2 = str2[b2 ... e2]
94
93
  alignment = TextAlignment::MixedAlignment.new(_str1.downcase, _str2.downcase, mappings)
95
- if alignment.similarity < 0.6
96
- @block_alignments << {source:{begin:b1, end:e1}, target:{begin:0, end:e2}, alignment: :empty}
94
+ similarity = alignment_similarity(_str1, _str2, alignment)
95
+ if similarity < 0.6
96
+ @block_alignment[:blocks] << {source:{begin:b1, end:e1}, target:{begin:0, end:e2}, alignment: :empty, similarity: similarity}
97
97
  else
98
- @block_alignments << {source:{begin:b1, end:e1}, target:{begin:0, end:e2}, alignment:alignment}
98
+ @block_alignment[:blocks] << {source:{begin:b1, end:e1}, target:{begin:0, end:e2}, alignment:alignment}
99
99
  end
100
100
  end
101
101
  end
102
102
  end
103
103
  end
104
- @block_alignments << mblocks[0].merge(alignment: :block)
104
+ @block_alignment[:blocks] << mblocks[0].merge(alignment: :block)
105
105
 
106
106
  (1 ... mblocks.length).each do |i|
107
107
  b1 = mblocks[i - 1][:source][:end]
@@ -112,17 +112,18 @@ class TextAlignment::TextAlignment
112
112
  _str2 = str2[b2 ... e2]
113
113
  unless _str1.strip.empty?
114
114
  if _str2.strip.empty?
115
- @block_alignments << {source:{begin:b1, end:e1}, target:{begin:b2, end:e2}, alignment: :empty}
115
+ @block_alignment[:blocks] << {source:{begin:b1, end:e1}, target:{begin:b2, end:e2}, alignment: :empty}
116
116
  else
117
117
  alignment = TextAlignment::MixedAlignment.new(_str1.downcase, _str2.downcase, mappings)
118
- if alignment.similarity < 0.6
119
- @block_alignments << {source:{begin:b1, end:e1}, target:{begin:b2, end:e2}, alignment: :empty}
118
+ similarity = alignment_similarity(_str1, _str2, alignment)
119
+ if similarity < 0.6
120
+ @block_alignment[:blocks] << {source:{begin:b1, end:e1}, target:{begin:b2, end:e2}, alignment: :empty, similarity: similarity}
120
121
  else
121
- @block_alignments << {source:{begin:b1, end:e1}, target:{begin:b2, end:e2}, alignment:alignment}
122
+ @block_alignment[:blocks] << {source:{begin:b1, end:e1}, target:{begin:b2, end:e2}, alignment:alignment}
122
123
  end
123
124
  end
124
125
  end
125
- @block_alignments << mblocks[i].merge(alignment: :block)
126
+ @block_alignment[:blocks] << mblocks[i].merge(alignment: :block)
126
127
  end
127
128
 
128
129
  # Final step
@@ -134,7 +135,7 @@ class TextAlignment::TextAlignment
134
135
 
135
136
  unless _str1.strip.empty?
136
137
  if _str2.strip.empty?
137
- @block_alignments << {source:{begin:b1, end:str1.length}, target:{begin:b2, end:str2.length}, alignment: :empty}
138
+ @block_alignment[:blocks] << {source:{begin:b1, end:str1.length}, target:{begin:b2, end:str2.length}, alignment: :empty}
138
139
  else
139
140
  len_min = [_str1.length, _str2.length].min
140
141
  len_buffer = (len_min * (1 + TextAlignment::BUFFER_RATE)).to_i + TextAlignment::BUFFER_MIN
@@ -144,57 +145,58 @@ class TextAlignment::TextAlignment
144
145
  _str2 = str2[b2 ... e2]
145
146
 
146
147
  alignment = TextAlignment::MixedAlignment.new(_str1.downcase, _str2.downcase, mappings)
147
- if alignment.similarity < 0.6
148
- @block_alignments << {source:{begin:b1, end:e1}, target:{begin:b2, end:e2}, alignment: :empty}
148
+ similarity = alignment_similarity(_str1, _str2, alignment)
149
+ if similarity < 0.6
150
+ @block_alignment[:blocks] << {source:{begin:b1, end:e1}, target:{begin:b2, end:e2}, alignment: :empty, similarity: similarity}
149
151
  else
150
- @block_alignments << {source:{begin:b1, end:e1}, target:{begin:b2, end:e2}, alignment:alignment}
152
+ @block_alignment[:blocks] << {source:{begin:b1, end:e1}, target:{begin:b2, end:e2}, alignment:alignment}
151
153
  end
152
154
 
153
- @block_alignments << {source:{begin:e1, end:-1}, target:{begin:e2, end:-1}, alignment: :empty} if e1 < str1.length
155
+ @block_alignment[:blocks] << {source:{begin:e1, end:-1}, target:{begin:e2, end:-1}, alignment: :empty} if e1 < str1.length
154
156
  end
155
157
  end
156
158
  end
157
159
 
158
- @block_alignments.each do |a|
160
+ @block_alignment[:blocks].each do |a|
159
161
  a[:delta] = a[:target][:begin] - a[:source][:begin]
160
162
  end
161
163
  end
162
164
 
163
165
  def transform_begin_position(begin_position)
164
- i = @block_alignments.index{|b| b[:source][:end] > begin_position}
165
- block_alignment = @block_alignments[i]
166
-
167
- b = if block_alignment[:alignment] == :block
168
- begin_position + block_alignment[:delta]
169
- elsif block_alignment[:alignment] == :empty
170
- if begin_position == block_alignment[:source][:begin]
171
- block_alignment[:target][:begin]
166
+ i = @block_alignment[:blocks].index{|b| b[:source][:end] > begin_position}
167
+ block = @block_alignment[:blocks][i]
168
+
169
+ b = if block[:alignment] == :block
170
+ begin_position + block[:delta]
171
+ elsif block[:alignment] == :empty
172
+ if begin_position == block[:source][:begin]
173
+ block[:target][:begin]
172
174
  else
173
175
  # raise "lost annotation"
174
176
  nil
175
177
  end
176
178
  else
177
- r = block_alignment[:alignment].transform_begin_position(begin_position - block_alignment[:source][:begin])
178
- r.nil? ? nil : r + block_alignment[:target][:begin]
179
+ r = block[:alignment].transform_begin_position(begin_position - block[:source][:begin])
180
+ r.nil? ? nil : r + block[:target][:begin]
179
181
  end
180
182
  end
181
183
 
182
184
  def transform_end_position(end_position)
183
- i = @block_alignments.index{|b| b[:source][:end] >= end_position}
184
- block_alignment = @block_alignments[i]
185
-
186
- e = if block_alignment[:alignment] == :block
187
- end_position + block_alignment[:delta]
188
- elsif block_alignment[:alignment] == :empty
189
- if end_position == block_alignment[:source][:end]
190
- block_alignment[:target][:end]
185
+ i = @block_alignment[:blocks].index{|b| b[:source][:end] >= end_position}
186
+ block = @block_alignment[:blocks][i]
187
+
188
+ e = if block[:alignment] == :block
189
+ end_position + block[:delta]
190
+ elsif block[:alignment] == :empty
191
+ if end_position == block[:source][:end]
192
+ block[:target][:end]
191
193
  else
192
194
  # raise "lost annotation"
193
195
  nil
194
196
  end
195
197
  else
196
- r = block_alignment[:alignment].transform_end_position(end_position - block_alignment[:source][:begin])
197
- r.nil? ? nil : r + block_alignment[:target][:begin]
198
+ r = block[:alignment].transform_end_position(end_position - block[:source][:begin])
199
+ r.nil? ? nil : r + block[:target][:begin]
198
200
  end
199
201
  end
200
202
 
@@ -240,87 +242,23 @@ class TextAlignment::TextAlignment
240
242
  r
241
243
  end
242
244
 
243
- def alignment_table
244
- table = <<-TABLE
245
- <table class='text_alignment_table'>
246
- <thead>
247
- <tr>
248
- <th class='text_alignment_left' style='width:50%'>Text 1</th>
249
- <th class='text_alignment_rigt'>Text 2</th>
250
- </tr>
251
- </thead>
252
- <tbody>
253
- TABLE
254
-
255
- @block_alignments.each do |a|
256
- table += alignment_table_th(a)
257
- table += "<tr>\n" + case a[:alignment]
258
- when :block
259
- "<td colspan='2' class='text_alignment_common'>" +
260
- @ostr1[a[:source][:begin] ... a[:source][:end]] +
261
- "</td>\n"
262
- when :empty
263
- "<td class='text_alignment_left'>" + @ostr1[a[:source][:begin] ... a[:source][:end]] + "</td>\n" +
264
- "<td class='text_alignment_right'>" + @ostr2[a[:target][:begin] ... a[:target][:end]] + "</td>\n"
265
- else
266
- base = a[:source][:begin]
267
- astr1 = a[:alignment].sdiff.map do |c|
268
- case c.action
269
- when '='
270
- @ostr1[c.old_position + base]
271
- when '+'
272
- '_'
273
- when '-'
274
- @ostr1[c.old_position + base]
275
- when '!'
276
- @ostr1[c.old_position + base] + '_'
277
- end
278
- end.join('')
279
-
280
- base = a[:target][:begin]
281
- astr2 = a[:alignment].sdiff.map do |c|
282
- case c.action
283
- when '='
284
- @ostr2[c.new_position + base]
285
- when '+'
286
- @ostr2[c.new_position + base]
287
- when '-'
288
- '_'
289
- when '!'
290
- '_' + @ostr2[c.new_position + base]
291
- end
292
- end.join('')
293
-
294
- "<td class='text_alignment_left'>" + astr1 + "</td>\n" +
295
- "<td class='text_alignment_right'>" + astr2 + "</td>\n"
296
- end + "</tr>\n"
297
- end
298
- table += '</tbody></table>'
299
- end
300
-
301
- def alignment_table_th(a)
302
- "<tr>" +
303
- "<th class='text_alignment_left'>#{a[:source][:begin]} - #{a[:source][:end]}</th>" +
304
- "<th class='text_alignment_right'>#{a[:target][:begin]} - #{a[:target][:end]}</th>" +
305
- "</tr>"
306
- end
307
-
308
245
  def alignment_show
246
+ stext = @block_alignment[:source_text]
247
+ ttext = @block_alignment[:target_text]
248
+
309
249
  show = ''
310
- @block_alignments.each do |a|
250
+ @block_alignment[:blocks].each do |a|
311
251
  show += case a[:alignment]
312
252
  when :block
313
253
  "===== common =====\n" +
314
- @ostr1[a[:source][:begin] ... a[:source][:end]] + "\n\n"
254
+ stext[a[:source][:begin] ... a[:source][:end]] + "\n\n"
315
255
  when :empty
316
- puts "<<<<< string 1"
317
- p @ostr1[a[:source][:begin] ... a[:source][:end]]
318
- puts
319
- puts ">>>>> string 2"
320
- p @ostr2[a[:target][:begin] ... a[:target][:end]]
321
- puts
256
+ "xxxxx disparate texts (similarity: #{a[:similarity]})\n" +
257
+ "<<<<< string 1\n" +
258
+ stext[a[:source][:begin] ... a[:source][:end]] + "\n\n" +
259
+ ">>>>> string 2\n" +
260
+ ttext[a[:target][:begin] ... a[:target][:end]] + "\n\n"
322
261
  else
323
- puts "***** local mismatch"
324
262
  astr1 = ''
325
263
  astr2 = ''
326
264
 
@@ -328,13 +266,13 @@ class TextAlignment::TextAlignment
328
266
  astr1 = a[:alignment].sdiff.map do |c|
329
267
  case c.action
330
268
  when '='
331
- @ostr1[c.old_position + base]
269
+ stext[c.old_position + base]
332
270
  when '+'
333
271
  '_'
334
272
  when '-'
335
- @ostr1[c.old_position + base]
273
+ stext[c.old_position + base]
336
274
  when '!'
337
- @ostr1[c.old_position + base] + '_'
275
+ stext[c.old_position + base] + '_'
338
276
  end
339
277
  end.join('')
340
278
 
@@ -342,21 +280,22 @@ class TextAlignment::TextAlignment
342
280
  astr2 = a[:alignment].sdiff.map do |c|
343
281
  case c.action
344
282
  when '='
345
- @ostr2[c.new_position + base]
283
+ ttext[c.new_position + base]
346
284
  when '+'
347
- @ostr2[c.new_position + base]
285
+ ttext[c.new_position + base]
348
286
  when '-'
349
287
  '_'
350
288
  when '!'
351
- '_' + @ostr2[c.new_position + base]
289
+ '_' + ttext[c.new_position + base]
352
290
  end
353
291
  end.join('')
354
292
 
355
- puts '[' + astr1 + ']'
356
- puts '[' + astr2 + ']'
357
- puts
293
+ "***** local mismatch\n" +
294
+ "[#{astr1}]\n" +
295
+ "[#{astr2}]\n\n"
358
296
  end
359
297
  end
298
+ show
360
299
  end
361
300
 
362
301
  private
@@ -381,15 +320,15 @@ class TextAlignment::TextAlignment
381
320
  pletters = TextAlignment::PADDING_LETTERS
382
321
 
383
322
  # find the padding letter for str1
384
- padding_letter1 = begin
323
+ @padding_letter1 = begin
385
324
  i = pletters.index{|l| str2.index(l).nil?}
386
325
  raise RuntimeError, "Could not find a padding letter for str1" if i.nil?
387
326
  TextAlignment::PADDING_LETTERS[i]
388
327
  end
389
328
 
390
329
  # find the padding letter for str2
391
- padding_letter2 = begin
392
- i = pletters.index{|l| l != padding_letter1 && str1.index(l).nil?}
330
+ @padding_letter2 = begin
331
+ i = pletters.index{|l| l != @padding_letter1 && str1.index(l).nil?}
393
332
  raise RuntimeError, "Could not find a padding letter for str2" if i.nil?
394
333
  TextAlignment::PADDING_LETTERS[i]
395
334
  end
@@ -400,12 +339,12 @@ class TextAlignment::TextAlignment
400
339
  from = f[1]
401
340
 
402
341
  if str2.index(f[0])
403
- to = f[0] + (padding_letter1 * (f[1].length - 1))
342
+ to = f[0] + (@padding_letter1 * (f[1].length - 1))
404
343
  str1.gsub!(from, to)
405
344
  end
406
345
 
407
346
  if str1.index(f[0])
408
- to = f[0] + (padding_letter2 * (f[1].length - 1))
347
+ to = f[0] + (@padding_letter2 * (f[1].length - 1))
409
348
  str2.gsub!(from, to)
410
349
  end
411
350
  end
@@ -414,4 +353,16 @@ class TextAlignment::TextAlignment
414
353
  [str1, str2, mappings]
415
354
  end
416
355
 
356
+ def alignment_similarity(_s1, _s2, alignment)
357
+ return 0 if alignment.sdiff.nil?
358
+
359
+ # compute the lcs only with non-whitespace letters
360
+ lcs = alignment.sdiff.count{|d| d.action == '=' && d.old_element =~ /\S/ && d.new_element =~ /\S/}
361
+
362
+ s1 = _s1.tr(@padding_letter1, ' ')
363
+ s2 = _s2.tr(@padding_letter2, ' ')
364
+
365
+ similarity = 2 * lcs / (s1.scan(/\S/).count + s2.scan(/\S/).count).to_f
366
+ end
367
+
417
368
  end
@@ -1,3 +1,3 @@
1
1
  class TextAlignment
2
- VERSION = '0.5'
2
+ VERSION = '0.6.2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: text_alignment
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.5'
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jin-Dong Kim
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-04 00:00:00.000000000 Z
11
+ date: 2020-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-dictionary