util 0.4.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.
@@ -0,0 +1,180 @@
1
+ results = [:ok, 42, nil, :ok, nil, nil, :err, :nope, nil]
2
+ results += [:err, nil, nil, :err, :nope, 'Temp#my_func']
3
+ $test.register 'result-new', results do ||
4
+ require 'util/result'
5
+ res = []
6
+ success = Util::Result.ok 42
7
+ res << success.instance_variable_get('@type')
8
+ res << success.instance_variable_get('@content')
9
+ res << success.instance_variable_get('@where')
10
+
11
+ success = Util::Result.ok
12
+ res << success.instance_variable_get('@type')
13
+ res << success.instance_variable_get('@content')
14
+ res << success.instance_variable_get('@where')
15
+
16
+ failure = Util::Result.err :nope
17
+ res << failure.instance_variable_get('@type')
18
+ res << failure.instance_variable_get('@content')
19
+ res << failure.instance_variable_get('@where')
20
+
21
+ failure = Util::Result.err
22
+ res << failure.instance_variable_get('@type')
23
+ res << failure.instance_variable_get('@content')
24
+ res << failure.instance_variable_get('@where')
25
+
26
+ class Temp
27
+ def my_func
28
+ Util::Result.err :nope, self
29
+ end
30
+ end
31
+
32
+ failure = Temp.new.my_func
33
+ res << failure.instance_variable_get('@type')
34
+ res << failure.instance_variable_get('@content')
35
+ res << failure.instance_variable_get('@where')
36
+
37
+ res
38
+ end
39
+
40
+ results = [true, false, false, false, true, false, false, true]
41
+ $test.register 'result-compare', results do ||
42
+ require 'util/result'
43
+ [ Util::Result.ok == Util::Result.ok,
44
+ Util::Result.ok == Util::Result.err,
45
+ Util::Result.ok == Util::Result.ok(42),
46
+ Util::Result.ok(42.0) == Util::Result.ok(42),
47
+ Util::Result.ok(42) == Util::Result.ok(42),
48
+ Util::Result.ok(42) == Util::Result.err(79),
49
+ Util::Result.ok(Object.new) == Util::Result.err(Object.new),
50
+ Util::Result.ok != Util::Result.err
51
+ ]
52
+ end
53
+
54
+ results = [true, false, false, true, false, true]
55
+ $test.register 'result-type-determiner', results do ||
56
+ require 'util/result'
57
+ class Temp
58
+ def self.divide num, denom
59
+ return Util::Result.err :div0, self if denom == 0
60
+ Util::Result.ok num / denom
61
+ end
62
+ end
63
+ [ Util::Result.ok(42).ok?,
64
+ Util::Result.ok(42).err?,
65
+ Util::Result.err(:nope, self).ok?,
66
+ Util::Result.err(:nope, self).err?,
67
+ Temp.divide(42, 7).err?,
68
+ Temp.divide(42, 0).err?,
69
+ ]
70
+ end
71
+
72
+ results = [6, 6, :nope, :div0, :div0, :nope]
73
+ $test.register 'result-retrieve-value', results do ||
74
+ require 'util/result'
75
+ class Temp
76
+ def self.divide num, denom
77
+ return Util::Result.err :div0, self if denom == 0
78
+ Util::Result.ok num / denom
79
+ end
80
+ end
81
+ [ Temp.divide(42, 7).value,
82
+ Temp.divide(42, 7).value_or(:nope),
83
+ Temp.divide(42, 0).value_or(:nope),
84
+ Temp.divide(42, 0).error,
85
+ Temp.divide(42, 0).error_or(:nope),
86
+ Temp.divide(42, 7).error_or(:nope),
87
+ ]
88
+ end
89
+
90
+ $test.register 'result-value-on-failure', ArgumentError do ||
91
+ require 'util/result'
92
+ class Temp
93
+ def self.divide num, denom
94
+ return Util::Result.err :div0, self if denom == 0
95
+ Util::Result.ok num / denom
96
+ end
97
+ end
98
+ Temp.divide(42, 0).value
99
+ end
100
+
101
+ $test.register 'result-error-on-success', ArgumentError do ||
102
+ require 'util/result'
103
+ class Temp
104
+ def self.divide num, denom
105
+ return Util::Result.err :div0, self if denom == 0
106
+ Util::Result.ok num / denom
107
+ end
108
+ end
109
+ Temp.divide(42, 7).error
110
+ end
111
+
112
+ results = ['[+] ', '[-] ', '[+] 6', '[- Temp.divide] div0']
113
+ $test.register 'result-to_s', results do ||
114
+ require 'util/result'
115
+ class Temp
116
+ def self.divide num, denom
117
+ return Util::Result.err :div0, self if denom == 0
118
+ Util::Result.ok num / denom
119
+ end
120
+ end
121
+ [ Util::Result.ok.to_s,
122
+ Util::Result.err.to_s,
123
+ Temp.divide(42, 7).to_s,
124
+ Temp.divide(42, 0).to_s,
125
+ ]
126
+ end
127
+
128
+ def next_num num
129
+ num.content + 1
130
+ end
131
+
132
+ results = [121, 122, 133, 133, :div0, 'Num#divide', 91, :div0, 'Num#divide']
133
+ results += [NameError, 'undefined method `substract\' for class `Num\'']
134
+ results += ['Util::Result#bind_common']
135
+ $test.register 'result-binding', results do ||
136
+ require 'util/result'
137
+
138
+ class Num
139
+ attr_reader :content
140
+ def initialize num
141
+ @content = num.to_f
142
+ end
143
+
144
+ def self.add first, second
145
+ Util::Result.ok Num.new(first.content + second.content)
146
+ end
147
+
148
+ def == num
149
+ return false unless num.respond_to?(:to_f)
150
+ @content.to_f == num.to_f
151
+ end
152
+
153
+ def add num
154
+ Util::Result.ok Num.new(@content + num.to_f)
155
+ end
156
+
157
+ def divide denom
158
+ return Util::Result.err :div0, self if denom == 0
159
+ Util::Result.ok Num.new(@content / denom.to_f)
160
+ end
161
+ end
162
+
163
+ base = Num.add(Num.new(42), Num.new(79))
164
+ [ base.value_or(:nope),
165
+ base.bind(:next_num).value_or(:nope), # Top-level method
166
+ base.bindm(:add, 12).value_or(:nope), # Instance method
167
+ base.bindcm(:add, Num.new(12)).value_or(:nope), # Class method
168
+ base.bindm(:divide, 0).error, # Failure
169
+ base.bindm(:divide, 0).where,
170
+ base.bindm(:add, 12).bindcm(:add, Num.new(-42)).value_or(:nope),
171
+ # Chain multiple binds
172
+ base.bindm(:add, 12).bindm(:divide, 0).bindcm(:add, Num.new(-42)).error,
173
+ base.bindm(:add, 12).bindm(:divide, 0).bindcm(:add, Num.new(-42)).where,
174
+ # Chain multiple binds with an error in between
175
+ base.bindm(:substract, 12).error.class,
176
+ base.bindm(:substract, 12).error.message,
177
+ base.bindm(:substract, 12).where,
178
+ # The method does not exist, hence raises an exception
179
+ ]
180
+ end
@@ -0,0 +1,235 @@
1
+ # Generates a YAML file containing all ISO 639-3 codes and information
2
+ # about them, from the lists distributed by the SIL.
3
+ #
4
+ # See `$0 --help` for command-line options.
5
+ # See main `LICENSES` file for license information.
6
+ # @author Guillaume Lestringant
7
+ # @version 1.0
8
+ # @note This program is supposed to not raise any exception, so that
9
+ # it can be called from a script (cf. `-q` option).
10
+ require 'optparse'
11
+ require 'yaml'
12
+
13
+ def log type, msg
14
+ code = { :none => "\033[0m", :ok => "\033[32m",
15
+ :err => "\033[31m", :warn => "\033[33m" }
16
+ text = { :none => '', :ok => '', :err => '[ERROR] ', :warn => '[WARNING] ' }
17
+
18
+ unless $options[:quiet] then
19
+ $options[:stderr_log] \
20
+ ? $STDERR.puts("#{code[type]}#{text[type]}#{msg}#{code[:none]}")
21
+ : puts("#{code[type]}#{text[type]}#{msg}#{code[:none]}")
22
+ end
23
+
24
+ exit 1 if type == :err
25
+ end
26
+
27
+ # Parse command-line options
28
+ ###########################
29
+
30
+ $options = {
31
+ :dest => 'iso639-3.yml',
32
+ :force => false,
33
+ :quiet => false,
34
+ :src_b => 'iso639-3',
35
+ :src_d => 'iso639-3d',
36
+ :src_m => 'iso639-3m',
37
+ :stderr_log => false,
38
+ }
39
+
40
+ OptionParser.new do |opts|
41
+ DEPR_TEXT = "List of deprecated codes. [DEF: #{$options[:src_d]}(.txt)]"
42
+ DEST_TEXT = "The file that will be generated. [DEF: #{$options[:dest]}(.txt)]"
43
+ FORCE_TEXT = 'Write destination even if file already exists. [DEF: false]'
44
+ HELP_TEXT = 'Display this help message.'
45
+ MACRO_TEXT = "List of macrolanguage mappings. [DEF: #{$options[:src_m]}(.txt)]"
46
+ QUIET_TEXT = 'Do not diplay anything in terminal. [DEF: false]'
47
+ SRC_TEXT = "List of active codes. [DEF: #{$options[:src_b]}(.txt)]"
48
+ STDERR_TEXT = 'Log to STDERR instead of STDOUT. [DEF: false]'
49
+ VERSION_TEXT = 'Print program version.'
50
+ NAME = 'Create ISO 639-3'
51
+ VERSION = '1.0'
52
+
53
+ opts.banner = "Usage: #{$0} [options]"
54
+
55
+ opts.on("-d", "--depr FILE", String, DEPR_TEXT) do |f|
56
+ $options[:src_d] = f
57
+ end
58
+
59
+ opts.on("-f", "--force", FORCE_TEXT) do |f|
60
+ $options[:force] = true
61
+ end
62
+
63
+ opts.on("-h", "--help", HELP_TEXT) do |h|
64
+ puts opts
65
+ exit
66
+ end
67
+
68
+ opts.on("-l", "--log-to-stderr", STDERR_TEXT) do |f|
69
+ $options[:stderr_log] = true
70
+ end
71
+
72
+ opts.on("-m", "--macro FILE", String, MACRO_TEXT) do |f|
73
+ $options[:src_m] = f
74
+ end
75
+
76
+ opts.on("-o", "--output FILE", String, DEST_TEXT) do |f|
77
+ $options[:dest] = f
78
+ end
79
+
80
+ opts.on("-q", "--quiet", QUIET_TEXT) do |f|
81
+ $options[:quiet] = true
82
+ end
83
+
84
+ opts.on("-s", "--src FILE", String, SRC_TEXT) do |f|
85
+ $options[:src_b] = f
86
+ end
87
+
88
+ opts.on("-v", "--version", VERSION_TEXT) do |v|
89
+ puts "#{NAME} v. #{VERSION}"
90
+ exit
91
+ end
92
+ end.parse!
93
+
94
+ log :none, "#{NAME} v. #{VERSION}"
95
+
96
+ # Check all parameters
97
+ #####################
98
+
99
+ def check_src idx, default
100
+ return if File.exist? $options[idx]
101
+
102
+ log :warn, "File not found `#{$options[idx]}`."
103
+ $options[idx] = File.extname($options[idx]) == '.txt' \
104
+ ? File.basename($options[idx], '.txt')
105
+ : $options[idx] + '.txt'
106
+ log :warn, "Trying `#{$options[idx]}` instead."
107
+ return if File.exist? $options[idx]
108
+
109
+ if $options[idx] == default or $options[idx] == (default + '.txt') then
110
+ log :err, 'File not found. No other possibility. Aborting.'
111
+ end
112
+
113
+ log :warn, "File not found. Reverting to default value `#{default}`."
114
+ $options[idx] = default
115
+ return if File.exist? $options[idx]
116
+
117
+ $options[idx] += '.txt'
118
+ log :warn, "File not found. Trying `#{$options[idx]}` instead."
119
+ return if File.exist? $options[idx]
120
+
121
+ log :err, 'File not found. No other possibility. Aborting.'
122
+ end
123
+
124
+ def mkdir_p dir
125
+ parent = File.dirname dir
126
+ log :err, "Root directory not found `#{dir}`." if dir == parent
127
+ mkdir_p parent unless File.exist? parent
128
+ log :err, "Not a directory `#{parent}`." unless File.directory? parent
129
+ Dir.mkdir dir
130
+ end
131
+
132
+ check_src :src_b, 'iso639-3'
133
+ check_src :src_d, 'iso639-3d'
134
+ check_src :src_m, 'iso639-3m'
135
+
136
+ if File.exist? $options[:dest] then
137
+ message = "File already exists `#{$options[:dest]}`. Use `-f` to overwrite."
138
+ log :err, message unless $options[:force]
139
+ else
140
+ dir = File.dirname $options[:dest]
141
+ mkdir_p dir unless File.exist? dir
142
+ log :err, "Not a directory `#{dir}`." unless File.directory? dir
143
+ end
144
+
145
+ log :ok, 'All parameters clear.'
146
+
147
+ # Extract the data
148
+ #################
149
+
150
+ keys = []
151
+ codes = {}
152
+ result = {}
153
+
154
+ active = File.read($options[:src_b]).lines[1..-1]
155
+ active = [] if active.nil?
156
+ active.each do |l|
157
+ id, part2b, part2t, part1, scope, type, name, comment = l.chomp.split "\t"
158
+
159
+ keys << id
160
+ id = id.to_sym
161
+ codes[id] = { :name => name }
162
+
163
+ case scope
164
+ when 'I' then codes[id][:scope] = :individual
165
+ when 'M' then codes[id][:scope] = :macro
166
+ when 'S' then codes[id][:scope] = :special
167
+ else puts "Unknown scope for #{id} : #{scope}."
168
+ end
169
+
170
+ case type
171
+ when 'A' then codes[id][:type] = :ancient
172
+ when 'C' then codes[id][:type] = :constructed
173
+ when 'E' then codes[id][:type] = :extinct
174
+ when 'H' then codes[id][:type] = :historical
175
+ when 'L' then codes[id][:type] = :living
176
+ when 'S' then codes[id][:type] = :special
177
+ else puts "Unknown type for #{id} : #{type}."
178
+ end
179
+
180
+ codes[id][:p1] = part1.to_sym unless part1.empty?
181
+ codes[id][:p2b] = part2b.to_sym unless part2b.empty?
182
+ codes[id][:p2t] = part2t.to_sym unless part2t.empty?
183
+ codes[id][:comment] = comment unless comment.nil? or comment.empty?
184
+ end
185
+
186
+ log :ok, 'Extracted active codes.'
187
+
188
+ deprecated = File.read($options[:src_d]).lines[1..-1]
189
+ deprecated = [] if deprecated.nil?
190
+ deprecated.each do |l|
191
+ id, name, reason, new, comment, date = l.chomp.split "\t"
192
+
193
+ keys << id
194
+ id = id.to_sym
195
+ codes[id] = { :deprecated => true, :name => name }
196
+
197
+ case reason
198
+ when 'C' then codes[id][:reason] = :change
199
+ when 'D' then codes[id][:reason] = :duplicate
200
+ when 'N' then codes[id][:reason] = :non_existent
201
+ when 'S' then codes[id][:reason] = :split
202
+ when 'M' then codes[id][:reason] = :merge
203
+ else puts "Unknown deprecation reason for #{id} : #{reason}."
204
+ end
205
+
206
+ codes[id][:new] = new.to_sym unless new.empty?
207
+ codes[id][:comment] = comment unless comment.empty?
208
+ codes[id][:date] = date unless date.empty? or date.empty?
209
+ end
210
+
211
+ log :ok, 'Extracted deprecated codes.'
212
+
213
+ macro = File.read($options[:src_m]).lines[1..-1]
214
+ macro = [] if macro.nil?
215
+ macro.each do |l|
216
+ macro, member, status = l.chomp.split "\t"
217
+
218
+ macro, member = macro.to_sym, member.to_sym
219
+ codes[macro][:members] = [] if codes[macro][:members].nil?
220
+ codes[macro][:members] << member
221
+ codes[member][:macro] = macro
222
+ end
223
+
224
+ log :ok, 'Extracted macrolanguage mappings.'
225
+
226
+ # Export
227
+ #######
228
+
229
+ keys.sort.each do |k|
230
+ result[k.to_sym] = codes[k.to_sym]
231
+ end
232
+
233
+ File.write $options[:dest], result.to_yaml
234
+
235
+ log :ok, 'Full success.'
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: util
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - Guillaume Lestringant
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-12 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |2
14
+ A collection of diverse simple utilities without much anything to do
15
+ with one another. The main rationale is to reduce the time spent on
16
+ boilerplate like checking whether the arguments have the right type,
17
+ or introducing some basic internationalization. More detail in the README.
18
+ email: 5582173-guillel@users.noreply.gitlab.com
19
+ executables: []
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - ".yardopts"
24
+ - CECILL-C.EN
25
+ - CECILL-C.FR
26
+ - LICENSES.md
27
+ - README.md
28
+ - lib/util.rb
29
+ - lib/util/args.rb
30
+ - lib/util/communia.rb
31
+ - lib/util/console_logger.rb
32
+ - lib/util/downloader.rb
33
+ - lib/util/i18n.rb
34
+ - lib/util/lists.rb
35
+ - lib/util/lists/iso639.rb
36
+ - lib/util/result.rb
37
+ - lib/util/test.rb
38
+ - lib/util/yaml.rb
39
+ - share/lists/iso639-3.yml
40
+ - test/unit.rb
41
+ - test/unit/args.rb
42
+ - test/unit/downloader.rb
43
+ - test/unit/downloader/orig/simple.html
44
+ - test/unit/i18n.rb
45
+ - test/unit/i18n/CamelCase/eng.yml
46
+ - test/unit/i18n/CamelCase/fra.yml
47
+ - test/unit/i18n/aaj.yml
48
+ - test/unit/i18n/en.yml
49
+ - test/unit/i18n/fra.yml
50
+ - test/unit/i18n/i18n
51
+ - test/unit/i18n/prv.yml
52
+ - test/unit/i18n/void/fra.yml/Yes-git-I-need-this-folder-even-if-it-is-empty
53
+ - test/unit/i18n/αλιας/fra.yml
54
+ - test/unit/lists/iso639.rb
55
+ - test/unit/result.rb
56
+ - tools/create-iso639-3.rb
57
+ homepage: https://gitlab.com/guillel/util-gem
58
+ licenses:
59
+ - CECILL-C
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubygems_version: 3.1.2
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Collection of simple utilities to reduce boilerplate
80
+ test_files: []