icu_name 1.0.16 → 1.1.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.
- data/README.rdoc +11 -24
- data/lib/icu_name/name.rb +16 -34
- data/lib/icu_name/util.rb +33 -0
- data/lib/icu_name/version.rb +1 -1
- data/spec/name_spec.rb +1 -7
- data/spec/util_spec.rb +47 -19
- metadata +3 -35
data/README.rdoc
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
= ICU Tournament
|
2
2
|
|
3
|
-
Canonicalises and matches person names with Western European characters
|
3
|
+
Canonicalises and matches person names with Western European characters.
|
4
|
+
|
5
|
+
Note: version 1.1.0 dropped support for characters beyond codepoint 255 and became independent of activesupport and i18n.
|
4
6
|
|
5
7
|
== Installation
|
6
8
|
|
@@ -8,14 +10,12 @@ For ruby 1.9.2, 1.9.3, 2.0.0.
|
|
8
10
|
|
9
11
|
gem install icu_name
|
10
12
|
|
11
|
-
It depends on _active_support_ and _i18n_.
|
12
|
-
|
13
13
|
== Names
|
14
14
|
|
15
15
|
This class exists for two main purposes:
|
16
16
|
|
17
|
-
* to normalise to a common format the different ways names are typed in practice
|
18
|
-
* to be able to match two names even if they are not exactly the same
|
17
|
+
* to normalise to a common format the different ways Irish person names are typed in practice
|
18
|
+
* to be able to match two names even if they are not exactly the same in their original form
|
19
19
|
|
20
20
|
To create a name object, supply both the first and second names separately to the constructor.
|
21
21
|
|
@@ -36,7 +36,6 @@ supply the two separately. If the full name is supplied alone to the constructor
|
|
36
36
|
of where the first names end, then the last distinct name is assumed to be the last name.
|
37
37
|
|
38
38
|
bobby = ICU::Name.new(' bobby fischer ')
|
39
|
-
|
40
39
|
bobby.first # => 'Bobby'
|
41
40
|
bobby.last # => 'Fischer'
|
42
41
|
|
@@ -77,13 +76,11 @@ Some other ways last names are canonicalised are illustrated below:
|
|
77
76
|
== Characters and Encoding
|
78
77
|
|
79
78
|
The class can only cope with Latin characters, including those with diacritics (accents).
|
80
|
-
|
81
|
-
(e.g. "a", "è", "Ö")
|
82
|
-
character plus one or more diacritics (e.g. "ł" or "Ś") are preserved, while everything
|
83
|
-
else is removed.
|
79
|
+
Hyphens, single quotes (which represent apostophes) and letters in the ISO-8859-1 range
|
80
|
+
(e.g. "a", "è", "Ö") are preserved, while everything else is removed (unsupported).
|
84
81
|
|
85
82
|
ICU::Name.new('éric', 'PRIÉ').name # => "Éric Prié"
|
86
|
-
ICU::Name.new('BARTŁOMIEJ', 'śliwa').name # => "
|
83
|
+
ICU::Name.new('BARTŁOMIEJ', 'śliwa').name # => "Bartomiej Liwa"
|
87
84
|
ICU::Name.new('Սմբատ', 'Լպուտյան').name # => ""
|
88
85
|
|
89
86
|
The various accessors (<tt>first</tt>, <tt>last</tt>, <tt>name</tt>, <tt>rname</tt>, <tt>to_s</tt>, <tt>original</tt>) always return
|
@@ -101,21 +98,11 @@ Accented letters can be transliterated into their US-ASCII counterparts by setti
|
|
101
98
|
eric.rname(:chars => "US-ASCII") # => "Prie, Eric"
|
102
99
|
eric.original(:chars => "US-ASCII") # => "PRIE, eric"
|
103
100
|
|
104
|
-
Also possible is the preservation of ISO-8859-1 characters, but the transliteration of
|
105
|
-
all other accented characters:
|
106
|
-
|
107
|
-
joe = Name.new('Józef', 'Żabiński')
|
108
|
-
joe.rname # => "Żabiński, Józef"
|
109
|
-
joe.rname(:chars => "ISO-8859-1") # => "Zabinski, Józef"
|
110
|
-
joe.rname(:chars => "US-ASCII") # => "Zabinski, Jozef"
|
111
|
-
|
112
101
|
Note that the character encoding of the strings returned is still UTF-8 in all cases.
|
113
102
|
The same option also relaxes the need for accented characters to match exactly:
|
114
103
|
|
115
104
|
eric.match('Eric', 'Prie') # => false
|
116
105
|
eric.match('Eric', 'Prie', :chars => "US-ASCII") # => true
|
117
|
-
joe.match('Józef', 'Zabinski') # => false
|
118
|
-
joe.match('Józef', 'Zabinski', :chars => "ISO-8859-1") # => true
|
119
106
|
|
120
107
|
== Customization of Alternative Names
|
121
108
|
|
@@ -153,7 +140,7 @@ To change alternative name behaviour, you can replace the default alternatives
|
|
153
140
|
with a customized set perhaps stored in a database or a YAML file, as illustrated below:
|
154
141
|
|
155
142
|
data = YAML.load(File open "my_last_name_alternatives.yaml")
|
156
|
-
Name.load_alternatives(:
|
143
|
+
Name.load_alternatives(:last, data)
|
157
144
|
data = YAML.load(File open "my_first_name_alternatives.yaml")
|
158
145
|
Name.load_alternatives(:first, data)
|
159
146
|
|
@@ -173,8 +160,8 @@ so that now:
|
|
173
160
|
Name.new("Stephen", "Hanly").match("Steven", "Hanly") # => true
|
174
161
|
|
175
162
|
This kind of rule risks producing false positives - you must judge
|
176
|
-
|
177
|
-
|
163
|
+
whether that risk is outweighed by the benefits of being able to overcome
|
164
|
+
spelling mistakes in the context of your application.
|
178
165
|
|
179
166
|
Another use is to cater for English and Irish versions of the same name.
|
180
167
|
For example, for last names:
|
data/lib/icu_name/name.rb
CHANGED
@@ -1,7 +1,4 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
require 'active_support'
|
3
|
-
require 'active_support/inflector/transliterate'
|
4
|
-
require 'active_support/core_ext/string/multibyte'
|
5
2
|
|
6
3
|
module ICU
|
7
4
|
class Name
|
@@ -20,7 +17,6 @@ module ICU
|
|
20
17
|
@name2 = Util.to_utf8(name2.to_s)
|
21
18
|
originalize
|
22
19
|
canonicalize
|
23
|
-
repair
|
24
20
|
@first.freeze
|
25
21
|
@last.freeze
|
26
22
|
@original.freeze
|
@@ -94,13 +90,10 @@ module ICU
|
|
94
90
|
@original.gsub!(/\s+/, ' ')
|
95
91
|
end
|
96
92
|
|
97
|
-
# Transliterate characters to ASCII
|
93
|
+
# Transliterate characters to ASCII.
|
98
94
|
def transliterate(str, chars='US-ASCII')
|
99
|
-
|
100
|
-
|
101
|
-
ActiveSupport::Inflector.transliterate(str)
|
102
|
-
when /^(Windows|CP)-?1252|ISO-?8859-?1|Latin(-?1)?$/i
|
103
|
-
str.gsub(/./) { |m| m.ord < 256 ? m : ActiveSupport::Inflector.transliterate(m) }
|
95
|
+
if chars.match(/ASCII/i)
|
96
|
+
Util.transliterate(str)
|
104
97
|
else
|
105
98
|
str.dup
|
106
99
|
end
|
@@ -139,49 +132,38 @@ module ICU
|
|
139
132
|
def clean(name)
|
140
133
|
name.gsub!(/[`‘’′‛]/, "'")
|
141
134
|
name.gsub!(/./) do |m|
|
142
|
-
|
143
|
-
|
144
|
-
m.match(/^[-a-zA-Z\u{c0}-\u{d6}\u{d8}-\u{f6}\u{f8}-\u{ff}.'\s]$/) ? m : ''
|
145
|
-
else
|
146
|
-
# Keep ASCII characters with diacritics (e.g. Polish ł and Ś).
|
147
|
-
transliterate(m) == '?' ? '' : m
|
148
|
-
end
|
135
|
+
# Keep only hyphens, normal characters, accented Latin1, full stops, single quotes and spaces.
|
136
|
+
m.ord < 256 && m.match(/\A[-a-zA-Z\u{c0}-\u{d6}\u{d8}-\u{f6}\u{f8}-\u{ff}.'\s]\z/) ? m : ''
|
149
137
|
end
|
150
138
|
name.gsub!(/\./, ' ')
|
151
139
|
name.gsub!(/\s*-\s*/, '-')
|
152
140
|
name.gsub!(/'+/, "'")
|
153
|
-
name.strip
|
141
|
+
name.strip!
|
142
|
+
name = Util.downcase(name)
|
143
|
+
name.split(/\s+/).map do |n|
|
154
144
|
n.sub!(/^-+/, '')
|
155
145
|
n.sub!(/-+$/, '')
|
156
146
|
n.split(/-/).map do |p|
|
157
|
-
|
147
|
+
Util.capitalize(p)
|
158
148
|
end.join('-')
|
159
|
-
end.join(' ')
|
160
|
-
end
|
161
|
-
|
162
|
-
# Try to ensure the encoding is UTF-8. This wasn't necessary before but some upgrade caused a change
|
163
|
-
# in behaviour. Since UTF-8 and ASCII are compatible encodings, it's probably not necessary to do
|
164
|
-
# this but I like to keep everything in the same encoding.
|
165
|
-
def repair
|
166
|
-
@first.force_encoding('UTF-8') if @first.encoding.name == "US-ASCII"
|
167
|
-
@last.force_encoding('UTF-8') if @last.encoding.name == "US-ASCII"
|
149
|
+
end.join(' ')
|
168
150
|
end
|
169
151
|
|
170
|
-
# Apply final touches to finish canonicalising a first name
|
152
|
+
# Apply final touches to finish canonicalising a first name.
|
171
153
|
def finish_first(names)
|
172
154
|
names.gsub(/([A-Z\u{c0}-\u{de}])\b/, '\1.')
|
173
155
|
end
|
174
156
|
|
175
|
-
# Apply final touches to finish canonicalising a last name
|
157
|
+
# Apply final touches to finish canonicalising a last name.
|
176
158
|
def finish_last(names)
|
177
|
-
names.gsub!(/\b([A-Z\u{c0}-\u{de}]')([a-z\u{e0}-\u{ff}])/) { |m| $1
|
178
|
-
names.gsub!(/\b(Mc)([a-z\u{e0}-\u{ff}])/) { |m| $1
|
159
|
+
names.gsub!(/\b([A-Z\u{c0}-\u{de}]')([a-z\u{e0}-\u{ff}])/) { |m| $1 + Util.upcase($2) }
|
160
|
+
names.gsub!(/\b(Mc)([a-z\u{e0}-\u{ff}])/) { |m| $1 + Util.upcase($2) }
|
179
161
|
names.gsub!(/\bMac([a-z\u{e0}-\u{ff}])/) do |m|
|
180
162
|
letter = $1 # capitalize after "Mac" only if the original clearly indicates it
|
181
|
-
upper =
|
163
|
+
upper = Util.upcase(letter)
|
182
164
|
'Mac'.concat(@original.match(/\bMac#{upper}/) ? upper : letter)
|
183
165
|
end
|
184
|
-
names.gsub!(/\bO ([A-Z\u{c0}-\u{de}])/) { |m| "O'"
|
166
|
+
names.gsub!(/\bO ([A-Z\u{c0}-\u{de}])/) { |m| "O'" + $1 } # O Kelly => "O'Kelly"
|
185
167
|
names
|
186
168
|
end
|
187
169
|
|
data/lib/icu_name/util.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
module ICU
|
2
4
|
module Util
|
5
|
+
LOWER_CHARS = "àáâãäåæçèéêëìíîïñòóôõöøùúûüýþ"
|
6
|
+
UPPER_CHARS = "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÑÒÓÔÕÖØÙÚÛÜÝÞ"
|
7
|
+
ACCENTED_CHARS = "ÀÁÂÃÄÅÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝàáâãäåèéêëìíîïñòóôõöùúûüý"
|
8
|
+
UNACCENTED_CHARS = "AAAAAAEEEEIIIINOOOOOUUUUYaaaaaaeeeeiiiinooooouuuuy"
|
9
|
+
|
3
10
|
# Decide if a string is valid UTF-8 or not, returning true or false.
|
4
11
|
def self.is_utf8(str)
|
5
12
|
dup = str.dup
|
@@ -15,5 +22,31 @@ module ICU
|
|
15
22
|
dup.force_encoding("Windows-1252") if dup.encoding.name.match(/^(ASCII-8BIT|UTF-8)$/)
|
16
23
|
dup.encode("UTF-8")
|
17
24
|
end
|
25
|
+
|
26
|
+
# Upcase a UTF-8 string that might contain accented characters.
|
27
|
+
def self.upcase(str)
|
28
|
+
str = str.upcase
|
29
|
+
return str if str.ascii_only?
|
30
|
+
str.tr(LOWER_CHARS, UPPER_CHARS)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Downcase a UTF-8 string that might contain accented characters.
|
34
|
+
def self.downcase(str)
|
35
|
+
str = str.downcase
|
36
|
+
return str if str.ascii_only?
|
37
|
+
str.tr(UPPER_CHARS, LOWER_CHARS)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Capilalize a UTF-8 string that might contain accented characters.
|
41
|
+
def self.capitalize(str)
|
42
|
+
return str.capitalize if str.ascii_only? || !str.match(/\A(.)(.*)\z/)
|
43
|
+
upcase($1) + downcase($2)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Transliterate Latin-1 accented characters to ASCII.
|
47
|
+
def self.transliterate(str)
|
48
|
+
return str.dup if str.ascii_only?
|
49
|
+
str.tr(ACCENTED_CHARS, UNACCENTED_CHARS)
|
50
|
+
end
|
18
51
|
end
|
19
52
|
end
|
data/lib/icu_name/version.rb
CHANGED
data/spec/name_spec.rb
CHANGED
@@ -79,7 +79,7 @@ module ICU
|
|
79
79
|
|
80
80
|
it "characters and encoding" do
|
81
81
|
ICU::Name.new('éric', 'PRIÉ').name.should == "Éric Prié"
|
82
|
-
ICU::Name.new('BARTŁOMIEJ', 'śliwa').name.should == "
|
82
|
+
ICU::Name.new('BARTŁOMIEJ', 'śliwa').name.should == "Bartomiej Liwa"
|
83
83
|
ICU::Name.new('Սմբատ', 'Լպուտյան').name.should == ""
|
84
84
|
eric = Name.new('éric'.encode("ISO-8859-1"), 'PRIÉ'.force_encoding("ASCII-8BIT"))
|
85
85
|
eric.rname.should == "Prié, Éric"
|
@@ -88,15 +88,9 @@ module ICU
|
|
88
88
|
eric.original.encoding.name.should == "UTF-8"
|
89
89
|
eric.rname(:chars => "US-ASCII").should == "Prie, Eric"
|
90
90
|
eric.original(:chars => "US-ASCII").should == "PRIE, eric"
|
91
|
-
joe = Name.new('Józef', 'Żabiński')
|
92
|
-
joe.rname.should == "Żabiński, Józef"
|
93
|
-
joe.rname(:chars => "ISO-8859-1").should == "Zabinski, Józef"
|
94
|
-
joe.rname(:chars => "US-ASCII").should == "Zabinski, Jozef"
|
95
91
|
eric.match('Éric', 'Prié').should be_true
|
96
92
|
eric.match('Eric', 'Prie').should be_false
|
97
93
|
eric.match('Eric', 'Prie', :chars => "US-ASCII").should be_true
|
98
|
-
joe.match('Józef', 'Zabinski').should be_false
|
99
|
-
joe.match('Józef', 'Zabinski', :chars => "ISO-8859-1").should be_true
|
100
94
|
end
|
101
95
|
end
|
102
96
|
|
data/spec/util_spec.rb
CHANGED
@@ -4,34 +4,62 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
4
4
|
module ICU
|
5
5
|
describe Util do
|
6
6
|
context "#is_utf8" do
|
7
|
-
it "
|
8
|
-
Util.is_utf8("Resume".encode("US-ASCII")).
|
7
|
+
it "recognises some encodings as a special case of UTF-8" do
|
8
|
+
expect(Util.is_utf8("Resume".encode("US-ASCII"))).to be_true
|
9
|
+
expect(Util.is_utf8("Resume".encode("ASCII-8BIT"))).to be_true
|
10
|
+
expect(Util.is_utf8("Resume".encode("BINARY"))).to be_true
|
9
11
|
end
|
10
12
|
|
11
|
-
it "
|
12
|
-
Util.is_utf8("Résumé").
|
13
|
-
Util.is_utf8("δog").
|
13
|
+
it "recognises UTF-8" do
|
14
|
+
expect(Util.is_utf8("Résumé")).to be_true
|
15
|
+
expect(Util.is_utf8("δog")).to be_true
|
14
16
|
end
|
15
17
|
|
16
18
|
it "should recognize other encodings as not being UTF-8" do
|
17
|
-
Util.is_utf8("Résumé".encode("ISO-8859-1")).
|
18
|
-
Util.is_utf8("€50".encode("Windows-1252")).
|
19
|
-
Util.is_utf8("ひらがな".encode("Shift_JIS")).
|
20
|
-
Util.is_utf8("\xa3").
|
19
|
+
expect(Util.is_utf8("Résumé".encode("ISO-8859-1"))).to be_false
|
20
|
+
expect(Util.is_utf8("€50".encode("Windows-1252"))).to be_false
|
21
|
+
expect(Util.is_utf8("ひらがな".encode("Shift_JIS"))).to be_false
|
22
|
+
expect(Util.is_utf8("\xa3")).to be_false
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
26
|
context "#to_utf8" do
|
25
|
-
it "
|
26
|
-
Util.to_utf8("Resume").
|
27
|
-
Util.to_utf8("Resume".force_encoding("US-ASCII")).encoding.name.
|
28
|
-
Util.to_utf8("Résumé".encode("ISO-8859-1")).
|
29
|
-
Util.to_utf8("Résumé".encode("Windows-1252")).
|
30
|
-
Util.to_utf8("€50".encode("Windows-1252")).
|
31
|
-
Util.to_utf8("\xa350".force_encoding("ASCII-8BIT")).
|
32
|
-
Util.to_utf8("\xa350").
|
33
|
-
Util.to_utf8("ひらがな".encode("Shift_JIS")).
|
27
|
+
it "converts to UTF-8" do
|
28
|
+
expect(Util.to_utf8("Resume")).to eq "Resume"
|
29
|
+
expect(Util.to_utf8("Resume".force_encoding("US-ASCII")).encoding.name).to eq "UTF-8"
|
30
|
+
expect(Util.to_utf8("Résumé".encode("ISO-8859-1"))).to eq "Résumé"
|
31
|
+
expect(Util.to_utf8("Résumé".encode("Windows-1252"))).to eq "Résumé"
|
32
|
+
expect(Util.to_utf8("€50".encode("Windows-1252"))).to eq "€50"
|
33
|
+
expect(Util.to_utf8("\xa350".force_encoding("ASCII-8BIT"))).to eq "£50"
|
34
|
+
expect(Util.to_utf8("\xa350")).to eq "£50"
|
35
|
+
expect(Util.to_utf8("ひらがな".encode("Shift_JIS"))).to eq "ひらがな"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "#downcase" do
|
40
|
+
it "downcases characters in the Latin-1 range" do
|
41
|
+
expect(Util.downcase("Eric")).to eq "eric"
|
42
|
+
expect(Util.downcase("Éric")).to eq "éric"
|
43
|
+
expect(Util.downcase("ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÑÒÓÔÕÖØÙÚÛÜÝÞ")).to eq "àáâãäåæçèéêëìíîïñòóôõöøùúûüýþ"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "#upcase" do
|
48
|
+
it "upcases characters in the Latin-1 range" do
|
49
|
+
expect(Util.upcase("Gearoidin")).to eq "GEAROIDIN"
|
50
|
+
expect(Util.upcase("Gearóidín")).to eq "GEARÓIDÍN"
|
51
|
+
expect(Util.upcase("àáâãäåæçèéêëìíîïñòóôõöøùúûüýþ")).to eq "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÑÒÓÔÕÖØÙÚÛÜÝÞ"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "#capitalize" do
|
56
|
+
it "capitalizes strings that might contain accented characters" do
|
57
|
+
expect(Util.capitalize("gearoidin")).to eq "Gearoidin"
|
58
|
+
expect(Util.capitalize("GEAROIDIN")).to eq "Gearoidin"
|
59
|
+
expect(Util.capitalize("gEAróiDÍn")).to eq "Gearóidín"
|
60
|
+
expect(Util.capitalize("ériC")).to eq "Éric"
|
61
|
+
expect(Util.capitalize("ÉRIc")).to eq "Éric"
|
34
62
|
end
|
35
63
|
end
|
36
64
|
end
|
37
|
-
end
|
65
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: icu_name
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,40 +9,8 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-07-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: activesupport
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '0'
|
22
|
-
type: :runtime
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0'
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: i18n
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: '0'
|
38
|
-
type: :runtime
|
39
|
-
prerelease: false
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ! '>='
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: '0'
|
46
14
|
- !ruby/object:Gem::Dependency
|
47
15
|
name: bundler
|
48
16
|
requirement: !ruby/object:Gem::Requirement
|
@@ -143,7 +111,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
143
111
|
version: '0'
|
144
112
|
segments:
|
145
113
|
- 0
|
146
|
-
hash: -
|
114
|
+
hash: -2995260603720583581
|
147
115
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
116
|
none: false
|
149
117
|
requirements:
|