lewagon 0.0.1

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.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +0 -0
  3. data/History.md +0 -0
  4. data/License.txt +20 -0
  5. data/README.md +0 -0
  6. data/bin/lewagon +5 -0
  7. data/lib/helpers/base58.rb +22 -0
  8. data/lib/helpers/char.rb +66 -0
  9. data/lib/helpers/unique_generator.rb +60 -0
  10. data/lib/lewagon/it/batch380.rb +11 -0
  11. data/lib/lewagon/version.rb +5 -0
  12. data/lib/lewagon.rb +310 -0
  13. data/lib/locales/README.md +40 -0
  14. data/lib/locales/ar.yml +102 -0
  15. data/lib/locales/bg.yml +44 -0
  16. data/lib/locales/ca-CAT.yml +24 -0
  17. data/lib/locales/ca.yml +23 -0
  18. data/lib/locales/da-DK.yml +73 -0
  19. data/lib/locales/de-AT.yml +56 -0
  20. data/lib/locales/de-CH.yml +19 -0
  21. data/lib/locales/de.yml +174 -0
  22. data/lib/locales/ee.yml +61 -0
  23. data/lib/locales/en/README.md +13 -0
  24. data/lib/locales/en/batch380.yml +4 -0
  25. data/lib/locales/en-AU.yml +28 -0
  26. data/lib/locales/en-BORK.yml +4 -0
  27. data/lib/locales/en-CA.yml +37 -0
  28. data/lib/locales/en-GB.yml +14 -0
  29. data/lib/locales/en-IND.yml +25 -0
  30. data/lib/locales/en-MS.yml +47 -0
  31. data/lib/locales/en-NEP.yml +49 -0
  32. data/lib/locales/en-NG.yml +77 -0
  33. data/lib/locales/en-NZ.yml +163 -0
  34. data/lib/locales/en-PAK.yml +18 -0
  35. data/lib/locales/en-SG.yml +35 -0
  36. data/lib/locales/en-TH.yml +360 -0
  37. data/lib/locales/en-UG.yml +128 -0
  38. data/lib/locales/en-US.yml +103 -0
  39. data/lib/locales/en-ZA.yml +148 -0
  40. data/lib/locales/en-au-ocker.yml +33 -0
  41. data/lib/locales/en.yml +11 -0
  42. data/lib/locales/es-MX.yml +105 -0
  43. data/lib/locales/es.yml +94 -0
  44. data/lib/locales/fa.yml +12 -0
  45. data/lib/locales/fi-FI.yml +35 -0
  46. data/lib/locales/fr-CA.yml +91 -0
  47. data/lib/locales/fr-CH.yml +78 -0
  48. data/lib/locales/fr.yml +115 -0
  49. data/lib/locales/he.yml +27 -0
  50. data/lib/locales/hy.yml +411 -0
  51. data/lib/locales/id.yml +24 -0
  52. data/lib/locales/it.yml +70 -0
  53. data/lib/locales/ja.yml +101 -0
  54. data/lib/locales/ko.yml +40 -0
  55. data/lib/locales/lv.yml +55 -0
  56. data/lib/locales/nb-NO.yml +62 -0
  57. data/lib/locales/nl.yml +92 -0
  58. data/lib/locales/no.yml +7 -0
  59. data/lib/locales/pl.yml +77 -0
  60. data/lib/locales/pt-BR.yml +718 -0
  61. data/lib/locales/pt.yml +66 -0
  62. data/lib/locales/ru.yml +76 -0
  63. data/lib/locales/sk.yml +78 -0
  64. data/lib/locales/sv.yml +81 -0
  65. data/lib/locales/th.yml +380 -0
  66. data/lib/locales/tr.yml +40 -0
  67. data/lib/locales/uk.yml +86 -0
  68. data/lib/locales/vi.yml +68 -0
  69. data/lib/locales/zh-CN.yml +56 -0
  70. data/lib/locales/zh-TW.yml +29 -0
  71. metadata +251 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5a59249bc762cfa6daf8e175b35a9ec859631d6a91c491a7e037c978dd4c46c1
4
+ data.tar.gz: 9d4a6f53e49e0fcae7f4bc022644bdaa1faa77cab7116fe9f13ec7c1b5aacb44
5
+ SHA512:
6
+ metadata.gz: 3eea5ad6939d073a9921dc15a7252784bd91380c1e0a274b68803b5d40a4c9e20e94771f523b66b87803f60a0dadeec3d2a3f8ef24a1352dc2b66cef3aa7c658
7
+ data.tar.gz: 51f1cbb761a7b514bc84bbf40eef83565f9646b3db1c42b3b4277d959c94d62a9cca4c2322270953ae51c0ee980e621f656c64a13deff07dc0d15d8b3ee56228
data/CHANGELOG.md ADDED
File without changes
data/History.md ADDED
File without changes
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007-2019 Benjamin Curtis
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
File without changes
data/bin/lewagon ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ lib_path = File.expand_path('../lib', __dir__)
5
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LeWagon
4
+ module Base58
5
+ def self.encode(str)
6
+ alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
7
+ base = alphabet.size
8
+
9
+ lv = 0
10
+ str.split('').reverse.each_with_index { |v, i| lv += v.unpack('C')[0] * 256**i }
11
+
12
+ ret = +''
13
+ while lv.positive?
14
+ lv, mod = lv.divmod(base)
15
+ ret << alphabet[mod]
16
+ end
17
+
18
+ npad = str.match(/^#{0.chr}*/)[0].to_s.size
19
+ '1' * npad + ret.reverse
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LeWagon
4
+ module Char
5
+ def self.prepare(string)
6
+ result = romanize_cyrillic string
7
+ result = fix_umlauts result
8
+ result.gsub(/\W/, '').downcase
9
+ end
10
+
11
+ def self.fix_umlauts(string)
12
+ string.gsub(/[äöüß]/i) do |match|
13
+ case match.downcase
14
+ when 'ä' then 'ae'
15
+ when 'ö' then 'oe'
16
+ when 'ü' then 'ue'
17
+ when 'ß' then 'ss'
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.romanize_cyrillic(string)
23
+ if LeWagon::Config.locale == 'uk'
24
+ # Based on conventions abopted by BGN/PCGN for Ukrainian
25
+ uk_chars = {
26
+ 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'h', 'ґ' => 'g', 'д' => 'd',
27
+ 'е' => 'e', 'є' => 'ye', 'ж' => 'zh', 'з' => 'z', 'и' => 'y', 'і' => 'i',
28
+ 'ї' => 'yi', 'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
29
+ 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u',
30
+ 'ф' => 'f', 'х' => 'kh', 'ц' => 'ts', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shch',
31
+ 'ю' => 'yu', 'я' => 'ya',
32
+ 'А' => 'a', 'Б' => 'b', 'В' => 'v', 'Г' => 'h', 'Ґ' => 'g', 'Д' => 'd',
33
+ 'Е' => 'e', 'Є' => 'ye', 'Ж' => 'zh', 'З' => 'z', 'И' => 'y', 'І' => 'i',
34
+ 'Ї' => 'yi', 'Й' => 'y', 'К' => 'k', 'Л' => 'l', 'М' => 'm', 'Н' => 'n',
35
+ 'О' => 'o', 'П' => 'p', 'Р' => 'r', 'С' => 's', 'Т' => 't', 'У' => 'u',
36
+ 'Ф' => 'f', 'Х' => 'kh', 'Ц' => 'ts', 'Ч' => 'ch', 'Ш' => 'sh', 'Щ' => 'shch',
37
+ 'Ю' => 'yu', 'Я' => 'ya',
38
+ 'ь' => '' # Ignore symbol, because its standard presentation is not allowed in URLs
39
+ }
40
+ return string.gsub(/[а-яА-ЯіїєґІЇЄҐ]/, uk_chars)
41
+ end
42
+
43
+ if LeWagon::Config.locale == 'ru'
44
+ # Based on conventions abopted by BGN/PCGN for Russian
45
+ ru_chars = {
46
+ 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'h', 'д' => 'd', 'е' => 'e',
47
+ 'ё' => 'ye', 'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'y', 'к' => 'k',
48
+ 'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r',
49
+ 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'kh', 'ц' => 'ts',
50
+ 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shch', 'ы' => 'у', 'э' => 'e', 'ю' => 'yu',
51
+ 'я' => 'ya',
52
+ 'А' => 'a', 'Б' => 'b', 'В' => 'v', 'Г' => 'h', 'Д' => 'd', 'Е' => 'e',
53
+ 'Ё' => 'ye', 'Ж' => 'zh', 'З' => 'z', 'И' => 'i', 'Й' => 'y', 'К' => 'k',
54
+ 'Л' => 'l', 'М' => 'm', 'Н' => 'n', 'О' => 'o', 'П' => 'p', 'Р' => 'r',
55
+ 'С' => 's', 'Т' => 't', 'У' => 'u', 'Ф' => 'f', 'Х' => 'kh', 'Ц' => 'ts',
56
+ 'Ч' => 'ch', 'Ш' => 'sh', 'Щ' => 'shch', 'Ы' => 'у', 'Э' => 'e', 'Ю' => 'yu',
57
+ 'Я' => 'ya',
58
+ 'ь' => '', 'ъ' => '' # Ignore symbols, because its standard presentation is not allowed in URLs
59
+ }
60
+ return string.gsub(/[а-яА-Я]/, ru_chars)
61
+ end
62
+
63
+ string
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LeWagon
4
+ class UniqueGenerator
5
+ @marked_unique = Set.new # Holds names of generators with unique values
6
+
7
+ class << self
8
+ attr_reader :marked_unique
9
+ end
10
+
11
+ def initialize(generator, max_retries)
12
+ @generator = generator
13
+ @max_retries = max_retries
14
+ @previous_results = Hash.new { |hash, key| hash[key] = Set.new }
15
+ end
16
+
17
+ # rubocop:disable Style/MethodMissingSuper
18
+ def method_missing(name, *arguments)
19
+ self.class.marked_unique.add(self)
20
+
21
+ @max_retries.times do
22
+ result = @generator.public_send(name, *arguments)
23
+
24
+ next if @previous_results[[name, arguments]].include?(result)
25
+
26
+ @previous_results[[name, arguments]] << result
27
+ return result
28
+ end
29
+
30
+ raise RetryLimitExceeded, "Retry limit exceeded for #{name}"
31
+ end
32
+ # Have method_missing use ruby 2.x keywords if the method exists.
33
+ # This is necessary because the syntax for passing arguments (`...`)
34
+ # is invalid on versions before Ruby 2.7, so it can't be used.
35
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
36
+ # rubocop:enable Style/MethodMissingSuper
37
+
38
+ def respond_to_missing?(method_name, include_private = false)
39
+ method_name.to_s.start_with?('lewagon_') || super
40
+ end
41
+
42
+ RetryLimitExceeded = Class.new(StandardError)
43
+
44
+ def clear
45
+ @previous_results.clear
46
+ end
47
+
48
+ def self.clear
49
+ marked_unique.each(&:clear)
50
+ marked_unique.clear
51
+ end
52
+
53
+ def exclude(name, arguments, values)
54
+ values ||= []
55
+ values.each do |value|
56
+ @previous_results[[name, arguments]] << value
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LeWagon
4
+ class Batch380 < Base
5
+ class << self
6
+ def massi
7
+ fetch('batch380.massi')
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LeWagon #:nodoc:
4
+ VERSION = '0.0.1'
5
+ end
data/lib/lewagon.rb ADDED
@@ -0,0 +1,310 @@
1
+ # frozen_string_literal: true
2
+
3
+ mydir = __dir__
4
+
5
+ begin
6
+ require 'psych'
7
+ end
8
+
9
+ require 'i18n'
10
+ require 'set' # Fixes a bug in i18n 0.6.11
11
+
12
+ Dir.glob(File.join(File.dirname(__FILE__), 'helpers', '*.rb')).sort.each { |file| require file }
13
+
14
+ I18n.load_path += Dir[File.join(mydir, 'locales', '**/*.yml')]
15
+ I18n.reload! if I18n.backend.initialized?
16
+
17
+ module LeWagon
18
+ class Config
19
+ @locale = nil
20
+ @random = nil
21
+
22
+ class << self
23
+ attr_writer :locale
24
+ attr_writer :random
25
+
26
+ def locale
27
+ @locale || I18n.locale
28
+ end
29
+
30
+ def own_locale
31
+ @locale
32
+ end
33
+
34
+ def random
35
+ @random || Random::DEFAULT
36
+ end
37
+ end
38
+ end
39
+
40
+ class Base
41
+ Numbers = Array(0..9)
42
+ ULetters = Array('A'..'Z')
43
+ LLetters = Array('a'..'z')
44
+ Letters = ULetters + LLetters
45
+
46
+ class << self
47
+ NOT_GIVEN = Object.new
48
+
49
+ ## by default numerify results do not start with a zero
50
+ def numerify(number_string, leading_zero: false)
51
+ return number_string.gsub(/#/) { rand(10).to_s } if leading_zero
52
+
53
+ number_string.sub(/#/) { rand(1..9).to_s }.gsub(/#/) { rand(10).to_s }
54
+ end
55
+
56
+ def letterify(letter_string)
57
+ letter_string.gsub(/\?/) { sample(ULetters) }
58
+ end
59
+
60
+ def bothify(string)
61
+ letterify(numerify(string))
62
+ end
63
+
64
+ # Given a regular expression, attempt to generate a string
65
+ # that would match it. This is a rather simple implementation,
66
+ # so don't be shocked if it blows up on you in a spectacular fashion.
67
+ #
68
+ # It does not handle ., *, unbounded ranges such as {1,},
69
+ # extensions such as (?=), character classes, some abbreviations
70
+ # for character classes, and nested parentheses.
71
+ #
72
+ # I told you it was simple. :) It's also probably dog-slow,
73
+ # so you shouldn't use it.
74
+ #
75
+ # It will take a regex like this:
76
+ #
77
+ # /^[A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}$/
78
+ #
79
+ # and generate a string like this:
80
+ #
81
+ # "U3V 3TP"
82
+ #
83
+ def regexify(reg)
84
+ reg = reg.source if reg.respond_to?(:source) # Handle either a Regexp or a String that looks like a Regexp
85
+ reg
86
+ .gsub(%r{^\/?\^?}, '').gsub(%r{\$?\/?$}, '') # Ditch the anchors
87
+ .gsub(/\{(\d+)\}/, '{\1,\1}').gsub(/\?/, '{0,1}') # All {2} become {2,2} and ? become {0,1}
88
+ .gsub(/(\[[^\]]+\])\{(\d+),(\d+)\}/) { |_match| Regexp.last_match(1) * sample(Array(Range.new(Regexp.last_match(2).to_i, Regexp.last_match(3).to_i))) } # [12]{1,2} becomes [12] or [12][12]
89
+ .gsub(/(\([^\)]+\))\{(\d+),(\d+)\}/) { |_match| Regexp.last_match(1) * sample(Array(Range.new(Regexp.last_match(2).to_i, Regexp.last_match(3).to_i))) } # (12|34){1,2} becomes (12|34) or (12|34)(12|34)
90
+ .gsub(/(\\?.)\{(\d+),(\d+)\}/) { |_match| Regexp.last_match(1) * sample(Array(Range.new(Regexp.last_match(2).to_i, Regexp.last_match(3).to_i))) } # A{1,2} becomes A or AA or \d{3} becomes \d\d\d
91
+ .gsub(/\((.*?)\)/) { |match| sample(match.gsub(/[\(\)]/, '').split('|')) } # (this|that) becomes 'this' or 'that'
92
+ .gsub(/\[([^\]]+)\]/) { |match| match.gsub(/(\w\-\w)/) { |range| sample(Array(Range.new(*range.split('-')))) } } # All A-Z inside of [] become C (or X, or whatever)
93
+ .gsub(/\[([^\]]+)\]/) { |_match| sample(Regexp.last_match(1).split('')) } # All [ABC] become B (or A or C)
94
+ .gsub('\d') { |_match| sample(Numbers) }
95
+ .gsub('\w') { |_match| sample(Letters) }
96
+ end
97
+
98
+ # Helper for the common approach of grabbing a translation
99
+ # with an array of values and selecting one of them.
100
+ def fetch(key)
101
+ fetched = sample(translate("lewagon.#{key}"))
102
+ if fetched&.match(%r{^\/}) && fetched&.match(%r{\/$}) # A regex
103
+ regexify(fetched)
104
+ else
105
+ fetched
106
+ end
107
+ end
108
+
109
+ # Helper for the common approach of grabbing a translation
110
+ # with an array of values and returning all of them.
111
+ def fetch_all(key)
112
+ fetched = translate("lewagon.#{key}")
113
+ fetched = fetched.last if fetched.size <= 1
114
+ if !fetched.respond_to?(:sample) && fetched.match(%r{^\/}) && fetched.match(%r{\/$}) # A regex
115
+ regexify(fetched)
116
+ else
117
+ fetched
118
+ end
119
+ end
120
+
121
+ # Load formatted strings from the locale, "parsing" them
122
+ # into method calls that can be used to generate a
123
+ # formatted translation: e.g., "#{first_name} #{last_name}".
124
+ def parse(key)
125
+ fetched = fetch(key)
126
+ parts = fetched.scan(/(\(?)#\{([A-Za-z]+\.)?([^\}]+)\}([^#]+)?/).map do |prefix, kls, meth, etc|
127
+ # If the token had a class Prefix (e.g., Name.first_name)
128
+ # grab the constant, otherwise use self
129
+ cls = kls ? LeWagon.const_get(kls.chop) : self
130
+
131
+ # If an optional leading parentheses is not present, prefix.should == "", otherwise prefix.should == "("
132
+ # In either case the information will be retained for reconstruction of the string.
133
+ text = prefix
134
+
135
+ # If the class has the method, call it, otherwise fetch the transation
136
+ # (e.g., lewagon.phone_number.area_code)
137
+ text += if cls.respond_to?(meth)
138
+ cls.send(meth)
139
+ else
140
+ # Do just enough snake casing to convert PhoneNumber to phone_number
141
+ key_path = cls.to_s.split('::').last.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
142
+ fetch("#{key_path}.#{meth.downcase}")
143
+ end
144
+
145
+ # And tack on spaces, commas, etc. left over in the string
146
+ text + etc.to_s
147
+ end
148
+ # If the fetched key couldn't be parsed, then fallback to numerify
149
+ parts.any? ? parts.join : numerify(fetched)
150
+ end
151
+
152
+ # Call I18n.translate with our configured locale if no
153
+ # locale is specified
154
+ def translate(*args, **opts)
155
+ opts[:locale] ||= LeWagon::Config.locale
156
+ opts[:raise] = true
157
+ I18n.translate(*args, **opts)
158
+ rescue I18n::MissingTranslationData
159
+ opts[:locale] = :en
160
+
161
+ # Super-simple fallback -- fallback to en if the
162
+ # translation was missing. If the translation isn't
163
+ # in en either, then it will raise again.
164
+ disable_enforce_available_locales do
165
+ I18n.translate(*args, **opts)
166
+ end
167
+ end
168
+
169
+ # Executes block with given locale set.
170
+ def with_locale(tmp_locale = nil)
171
+ current_locale = LeWagon::Config.own_locale
172
+ LeWagon::Config.locale = tmp_locale
173
+
174
+ disable_enforce_available_locales do
175
+ I18n.with_locale(tmp_locale) { yield }
176
+ end
177
+ ensure
178
+ LeWagon::Config.locale = current_locale
179
+ end
180
+
181
+ def flexible(key)
182
+ @flexible_key = key
183
+ end
184
+
185
+ # You can add whatever you want to the locale file, and it will get caught here.
186
+ # E.g., in your locale file, create a
187
+ # name:
188
+ # girls_name: ["Alice", "Cheryl", "Tatiana"]
189
+ # Then you can call LeWagon::Name.girls_name and it will act like #first_name
190
+ def method_missing(mth, *args, &block)
191
+ super unless @flexible_key
192
+
193
+ if (translation = translate("lewagon.#{@flexible_key}.#{mth}"))
194
+ sample(translation)
195
+ else
196
+ super
197
+ end
198
+ end
199
+
200
+ def respond_to_missing?(method_name, include_private = false)
201
+ super
202
+ end
203
+
204
+ # Generates a random value between the interval
205
+ def rand_in_range(from, to)
206
+ from, to = to, from if to < from
207
+ rand(from..to)
208
+ end
209
+
210
+ # If an array or range is passed, a random value will be selected.
211
+ # All other values are simply returned.
212
+ def resolve(value)
213
+ case value
214
+ when Array then sample(value)
215
+ when Range then rand value
216
+ else value
217
+ end
218
+ end
219
+
220
+ # Return unique values from the generator every time.
221
+ #
222
+ # @param max_retries [Integer] The max number of retries that should be done before giving up.
223
+ # @return [self]
224
+ def unique(max_retries = 10_000)
225
+ @unique ||= UniqueGenerator.new(self, max_retries)
226
+ end
227
+
228
+ def sample(list)
229
+ list.respond_to?(:sample) ? list.sample(random: LeWagon::Config.random) : list
230
+ end
231
+
232
+ def shuffle(list)
233
+ list.shuffle(random: LeWagon::Config.random)
234
+ end
235
+
236
+ def rand(max = nil)
237
+ if max.nil?
238
+ LeWagon::Config.random.rand
239
+ elsif max.is_a?(Range) || max.to_i.positive?
240
+ LeWagon::Config.random.rand(max)
241
+ else
242
+ 0
243
+ end
244
+ end
245
+
246
+ def disable_enforce_available_locales
247
+ old_enforce_available_locales = I18n.enforce_available_locales
248
+ I18n.enforce_available_locales = false
249
+ yield
250
+ ensure
251
+ I18n.enforce_available_locales = old_enforce_available_locales
252
+ end
253
+
254
+ private
255
+
256
+ def warn_for_deprecated_arguments
257
+ keywords = []
258
+ yield(keywords)
259
+
260
+ return if keywords.empty?
261
+
262
+ method_name = caller.first.match(/`(?<method_name>.*)'/)[:method_name]
263
+
264
+ keywords.each.with_index(1) do |keyword, index|
265
+ i = case index
266
+ when 1 then '1st'
267
+ when 2 then '2nd'
268
+ when 3 then '3rd'
269
+ else "#{index}th"
270
+ end
271
+
272
+ warn_with_uplevel(<<~MSG, uplevel: 5)
273
+ Passing `#{keyword}` with the #{i} argument of `#{method_name}` is deprecated. Use keyword argument like `#{method_name}(#{keyword}: ...)` instead.
274
+ MSG
275
+ end
276
+
277
+ warn(<<~MSG)
278
+
279
+ To automatically update from positional arguments to keyword arguments,
280
+ install rubocop-lewagon and run:
281
+
282
+ rubocop \\
283
+ --require rubocop-lewagon \\
284
+ --only LeWagon/DeprecatedArguments \\
285
+ --auto-correct
286
+
287
+ MSG
288
+ end
289
+
290
+ # Workaround for emulating `warn '...', uplevel: 1` in Ruby 2.4 or lower.
291
+ def warn_with_uplevel(message, uplevel: 1)
292
+ at = parse_caller(caller[uplevel]).join(':')
293
+ warn "#{at}: #{message}"
294
+ end
295
+
296
+ def parse_caller(at)
297
+ # rubocop:disable Style/GuardClause
298
+ if /^(.+?):(\d+)(?::in `.*')?/ =~ at
299
+ file = Regexp.last_match(1)
300
+ line = Regexp.last_match(2).to_i
301
+ [file, line]
302
+ end
303
+ # rubocop:enable Style/GuardClause
304
+ end
305
+ end
306
+ end
307
+ end
308
+
309
+ # require lewagon objects
310
+ Dir.glob(File.join(File.dirname(__FILE__), 'lewagon', '/**/*.rb')).sort.each { |file| require file }
@@ -0,0 +1,40 @@
1
+ # How Locales Work
2
+
3
+ The default locale is English. You can see how it is implemented in the "translate" method in [LeWagon.rb](/lib/lewagon.rb).
4
+
5
+ Here's how to set it:
6
+
7
+ ```ruby
8
+ # Sets the locale to "Simplified Chinese":
9
+ LeWagon::Config.locale = 'zh-CN'
10
+ ```
11
+
12
+ It works so that once the LeWagon locale is set to a different location, the translate method will check that .yml file for an equivalent and use that data. If it doesn't exist, it defaults back to English. It uses the "i18n" gem to do this.
13
+
14
+ Using Chinese as an example, when the locale is set to Chinese and you attempt to call for hipster ipsem (which doesn't exist at the time of this writing), you will get English back. It checks the "zh-CH.yml" file, does not find "hipster" and then checks the "en.yml" file and returns a word from that array.
15
+
16
+ ```ruby
17
+ LeWagon::Config.locale = 'zh-CN'
18
+ LeWagon::Hipster.word #=> "kogi"
19
+ ```
20
+
21
+ In order to update a locale with more translation features, simply add a new field to the .yml file that corresponds to an existing piece of functionality in the "en.yml" file. In this example, that would mean providing Chinese hipster words.
22
+
23
+ ```yaml
24
+ # /lib/locales/zh-CN.yml
25
+ hipster:
26
+ - "屌丝"
27
+ ```
28
+
29
+ ```ruby
30
+ # Now this should work:
31
+ LeWagon::Hipster.word #=> "屌丝"
32
+ ```
33
+
34
+ After you've done that, find or create a test file for the locale you've updated and test the functionality for that language.
35
+
36
+ In our hypothetical example here, one would add something like this to the "test-zh-locale.rb" file in the "test_ch_methods" method:
37
+
38
+ ```ruby
39
+ assert LeWagon::Hipster.word.is_a? String
40
+ ```