monolens 0.6.0 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/monolens/command/tester.rb +95 -0
- data/lib/monolens/command.rb +33 -11
- data/lib/monolens/file.rb +5 -0
- data/lib/monolens/stdlib/core/mapping.rb +7 -1
- data/lib/monolens/version.rb +1 -1
- data/spec/monolens/command/test-ko-complex.yml +15 -0
- data/spec/monolens/command/test-ko.lens.yml +13 -0
- data/spec/monolens/command/test-ok.lens.yml +9 -0
- data/spec/monolens/stdlib/core/test_mapping.rb +41 -0
- data/spec/monolens/test_command.rb +34 -1
- metadata +35 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e0de27df8fbe83531b35a1b3c4b92d94669108ef10f17df849d9127a07698ad2
|
4
|
+
data.tar.gz: abf82eebdd9511578b0cd73524430335f9b9c8ecb60fe74598eec3e6c0d5f5e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3909ab4f03d872d0083884ddea46e3d2546caeef268c83e1145204789050c89e34cd219161a672e07a5b34727c40f21a23be501b85ea7aaed2dd9c1eb54abf66
|
7
|
+
data.tar.gz: 394d89daddae630912035d43eefc6ab1a591a45eee3b305b203983cc40c673ad83feb65a3c9510d9a6534311f5c70af7726c83356a64cc6c35a4d2e6949512ee
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'minitest'
|
2
|
+
require 'paint'
|
3
|
+
module Monolens
|
4
|
+
class Command
|
5
|
+
class Tester
|
6
|
+
include Minitest::Assertions
|
7
|
+
|
8
|
+
def initialize(command)
|
9
|
+
@command = command
|
10
|
+
@nb_tests = 0
|
11
|
+
@nb_successes = 0
|
12
|
+
@nb_errors = 0
|
13
|
+
@nb_failures = 0
|
14
|
+
Paint.mode = command.use_paint? ? Paint.detect_mode : 0
|
15
|
+
end
|
16
|
+
attr_accessor :nb_tests, :nb_successes, :nb_errors, :nb_failures
|
17
|
+
|
18
|
+
def call(lens)
|
19
|
+
fail!("No tests found (#{lens.class})") unless lens.is_a?(Monolens::File)
|
20
|
+
|
21
|
+
self.nb_tests = lens.examples.size
|
22
|
+
details = []
|
23
|
+
lens.examples.each_with_index do |example, i|
|
24
|
+
test_one(lens, example, i, details)
|
25
|
+
end
|
26
|
+
|
27
|
+
stdout.puts("\n")
|
28
|
+
stdout.puts("\n") unless details.empty?
|
29
|
+
details.each do |message|
|
30
|
+
stdout.puts(message)
|
31
|
+
end
|
32
|
+
|
33
|
+
success = nb_errors == 0 && nb_failures == 0
|
34
|
+
stdout.puts(success ? green(last_sentence) : red(last_sentence))
|
35
|
+
|
36
|
+
do_exit(1) unless success
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def last_sentence
|
42
|
+
sentence = "\n"
|
43
|
+
sentence << plural('test', nb_tests) << ". "
|
44
|
+
sentence << plural('success', nb_successes) << ", "
|
45
|
+
sentence << plural('failure', nb_failures) << ", "
|
46
|
+
sentence << plural('error', nb_errors) << "."
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_one(lens, example, i, details = [])
|
50
|
+
input, output = example[:input], example[:output]
|
51
|
+
result = lens.call(input)
|
52
|
+
if result == output
|
53
|
+
self.nb_successes += 1
|
54
|
+
stdout.print(green ".")
|
55
|
+
else
|
56
|
+
self.nb_failures += 1
|
57
|
+
stdout.print(red "F")
|
58
|
+
details << "Failure on example #{1+i}:\n#{diff output, result}"
|
59
|
+
end
|
60
|
+
rescue Monolens::Error => ex
|
61
|
+
self.nb_errors += 1
|
62
|
+
stdout.print("E")
|
63
|
+
details << "Error on example #{1+i}: #{ex.message}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def green(s)
|
67
|
+
Paint[s, :green]
|
68
|
+
end
|
69
|
+
|
70
|
+
def red(s)
|
71
|
+
Paint[s, :red]
|
72
|
+
end
|
73
|
+
|
74
|
+
def plural(who, nb)
|
75
|
+
if nb > 1
|
76
|
+
"#{nb} #{who}s"
|
77
|
+
else
|
78
|
+
"#{nb} #{who}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
[
|
83
|
+
:stdout,
|
84
|
+
:stderr,
|
85
|
+
:do_exit,
|
86
|
+
:fail!
|
87
|
+
].each do |name|
|
88
|
+
define_method(name) do |*args, &bl|
|
89
|
+
@command.send(name, *args, &bl)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/monolens/command.rb
CHANGED
@@ -16,14 +16,21 @@ module Monolens
|
|
16
16
|
@stream = false
|
17
17
|
@fail_strategy = 'fail'
|
18
18
|
@override = false
|
19
|
+
@execute_tests = false
|
19
20
|
#
|
20
21
|
@input_file = nil
|
21
22
|
@use_stdin = false
|
23
|
+
#
|
24
|
+
@use_paint = true
|
22
25
|
end
|
23
26
|
attr_reader :argv, :stdin, :stdout, :stderr
|
24
27
|
attr_reader :pretty, :stream, :override
|
25
28
|
attr_reader :enclose_map, :fail_strategy
|
26
29
|
attr_reader :input_file, :use_stdin
|
30
|
+
attr_reader :use_paint
|
31
|
+
alias :use_paint? :use_paint
|
32
|
+
attr_reader :execute_tests
|
33
|
+
alias :execute_tests? :execute_tests
|
27
34
|
|
28
35
|
def self.call(argv, stdin = $stdin, stdout = $stdout, stderr = $stderr)
|
29
36
|
new(argv, stdin, stdout, stderr).call
|
@@ -31,21 +38,30 @@ module Monolens
|
|
31
38
|
|
32
39
|
def call
|
33
40
|
lens, @input_file = options.parse!(argv)
|
34
|
-
show_help_and_exit if lens.nil? || (@input_file.nil? && !use_stdin)
|
41
|
+
show_help_and_exit if lens.nil? || (@input_file.nil? && !use_stdin && !execute_tests?)
|
35
42
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
43
|
+
lens = build_lens(read_file(lens))
|
44
|
+
if execute_tests?
|
45
|
+
execute_tests!(lens)
|
46
|
+
else
|
47
|
+
input = read_input
|
48
|
+
error_handler = ErrorHandler.new
|
49
|
+
result = lens.call(input, error_handler: error_handler)
|
40
50
|
|
41
|
-
|
42
|
-
|
43
|
-
|
51
|
+
unless error_handler.empty?
|
52
|
+
stderr.puts(error_handler.report)
|
53
|
+
end
|
44
54
|
|
45
|
-
|
55
|
+
output_result(result) if result
|
56
|
+
end
|
46
57
|
rescue Monolens::LensError => ex
|
47
58
|
stderr.puts("[#{ex.location.join('/')}] #{ex.message}")
|
48
|
-
do_exit(
|
59
|
+
do_exit(1)
|
60
|
+
end
|
61
|
+
|
62
|
+
def execute_tests!(lens)
|
63
|
+
require_relative 'command/tester'
|
64
|
+
Tester.new(self).call(lens)
|
49
65
|
end
|
50
66
|
|
51
67
|
def read_input
|
@@ -130,6 +146,12 @@ module Monolens
|
|
130
146
|
opts.on('--override', 'Write output back to the input file') do
|
131
147
|
@override = true
|
132
148
|
end
|
149
|
+
opts.on('--test', 'Execute tests embedded in the lens file') do
|
150
|
+
@execute_tests = true
|
151
|
+
end
|
152
|
+
opts.on('--[no-]paint', 'Do (not) paint error messages') do |flag|
|
153
|
+
@use_paint = flag
|
154
|
+
end
|
133
155
|
end
|
134
156
|
end
|
135
157
|
|
@@ -150,7 +172,7 @@ module Monolens
|
|
150
172
|
}
|
151
173
|
}
|
152
174
|
end
|
153
|
-
end
|
175
|
+
end unless execute_tests?
|
154
176
|
Monolens.lens(lens_data)
|
155
177
|
end
|
156
178
|
|
data/lib/monolens/file.rb
CHANGED
@@ -6,10 +6,15 @@ module Monolens
|
|
6
6
|
version: [Type::Any, true],
|
7
7
|
macros: [Type::Map.of(Type::Name, Type::Any), false],
|
8
8
|
lenses: [Type::Lenses, true],
|
9
|
+
examples: [Type::Array.of(Type::Map.of(Type::Name, Type::Any)), false],
|
9
10
|
})
|
10
11
|
|
11
12
|
def call(arg, world = {})
|
12
13
|
option(:lenses).call(arg, world)
|
13
14
|
end
|
15
|
+
|
16
|
+
def examples
|
17
|
+
option(:examples, [])
|
18
|
+
end
|
14
19
|
end
|
15
20
|
end
|
@@ -8,12 +8,18 @@ module Monolens
|
|
8
8
|
values: [Type::Object, false], # deprecated
|
9
9
|
default: [Type::Any, false],
|
10
10
|
fallback: [Type::Callback, false],
|
11
|
+
key_hash: [Type::Lenses, false],
|
11
12
|
on_missing: [Type::Strategy.missing(%w{default fail fallback keep null}), false]
|
12
13
|
})
|
13
14
|
|
14
15
|
def call(arg, world = {})
|
16
|
+
original_arg = arg
|
17
|
+
if key_hash = option(:key_hash, nil)
|
18
|
+
arg = key_hash.call(arg, world)
|
19
|
+
end
|
20
|
+
|
15
21
|
option(:defn, option(:values, {})).fetch(arg) do
|
16
|
-
on_missing(
|
22
|
+
on_missing(original_arg, world)
|
17
23
|
end
|
18
24
|
end
|
19
25
|
|
data/lib/monolens/version.rb
CHANGED
@@ -21,6 +21,47 @@ describe Monolens, 'core.mapping' do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
context 'with key_hash option' do
|
25
|
+
let(:mapping) do
|
26
|
+
{
|
27
|
+
'key_hash' => 'str.downcase',
|
28
|
+
'defn' => { 'todo' => 'open' }
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
subject do
|
33
|
+
Monolens.lens('core.mapping' => mapping)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'replaces the value by its mapped' do
|
37
|
+
expect(subject.call('todo')).to eql('open')
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'uses the key_hash before looking for mapping' do
|
41
|
+
expect(subject.call('TODO')).to eql('open')
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'raises if not found' do
|
45
|
+
expect {
|
46
|
+
subject.call('nosuchone')
|
47
|
+
}.to raise_error(Monolens::LensError)
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with on_missing: keep' do
|
51
|
+
subject do
|
52
|
+
Monolens.lens('core.mapping' => mapping.merge('on_missing' => 'keep'))
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'keeps it if missing' do
|
56
|
+
expect(subject.call('nosuchone')).to eql('nosuchone')
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'keeps the original one, not the key_hashed one' do
|
60
|
+
expect(subject.call('NOSUCHONE')).to eql('NOSUCHONE')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
24
65
|
context 'on_missing: default' do
|
25
66
|
subject do
|
26
67
|
Monolens.lens('core.mapping' => mapping.merge('on_missing' => 'default', 'default' => 'foo'))
|
@@ -235,13 +235,46 @@ module Monolens
|
|
235
235
|
end
|
236
236
|
end
|
237
237
|
|
238
|
+
context 'with --paint --test (ignoring --map, --literal)' do
|
239
|
+
let(:argv) do
|
240
|
+
['--map', '--literal', '--paint', '--test', FIXTURES/'test-ok.lens.yml']
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'works as expected' do
|
244
|
+
expect(stdout.string).to match(/1 test. 1 success, 0 failure, 0 error./)
|
245
|
+
expect(exit_status).to be_nil
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
context 'with --no-paint --test' do
|
250
|
+
let(:argv) do
|
251
|
+
['--no-paint', '--test', FIXTURES/'test-ok.lens.yml']
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'works as expected' do
|
255
|
+
expect(stdout.string).to eql(".\n\n1 test. 1 success, 0 failure, 0 error.\n")
|
256
|
+
expect(exit_status).to be_nil
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context 'with --no-paint --test with failures' do
|
261
|
+
let(:argv) do
|
262
|
+
['--no-paint', '--test', FIXTURES/'test-ko.lens.yml']
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'works as expected' do
|
266
|
+
expect(stdout.string).to eql("F.\n\nFailure on example 1:\nExpected: \"Monolens\"\n Actual: \"MONOLENS\"\n\n2 tests. 1 success, 1 failure, 0 error.\n")
|
267
|
+
expect(exit_status).to eql(1)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
238
271
|
context 'when yielding an error' do
|
239
272
|
let(:argv) do
|
240
273
|
[FIXTURES/'map-upcase.lens.yml', FIXTURES/'names-with-null.json']
|
241
274
|
end
|
242
275
|
|
243
276
|
it 'works as expected' do
|
244
|
-
expect(exit_status).to eql(
|
277
|
+
expect(exit_status).to eql(1)
|
245
278
|
expect(stdout.string).to eql('')
|
246
279
|
expect(stderr.string).to eql("[1] String expected, got NilClass\n")
|
247
280
|
end
|
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monolens
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bernard Lambeau
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.16'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: paint
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.3'
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: rake
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +108,7 @@ files:
|
|
80
108
|
- bin/monolens
|
81
109
|
- lib/monolens.rb
|
82
110
|
- lib/monolens/command.rb
|
111
|
+
- lib/monolens/command/tester.rb
|
83
112
|
- lib/monolens/error.rb
|
84
113
|
- lib/monolens/error_handler.rb
|
85
114
|
- lib/monolens/file.rb
|
@@ -154,6 +183,9 @@ files:
|
|
154
183
|
- spec/monolens/command/names-with-null.json
|
155
184
|
- spec/monolens/command/names.json
|
156
185
|
- spec/monolens/command/robust-map-upcase.lens.yml
|
186
|
+
- spec/monolens/command/test-ko-complex.yml
|
187
|
+
- spec/monolens/command/test-ko.lens.yml
|
188
|
+
- spec/monolens/command/test-ok.lens.yml
|
157
189
|
- spec/monolens/command/upcase.lens.yml
|
158
190
|
- spec/monolens/lens/test_options.rb
|
159
191
|
- spec/monolens/lens/test_signature.rb
|
@@ -210,8 +242,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
210
242
|
- !ruby/object:Gem::Version
|
211
243
|
version: '0'
|
212
244
|
requirements: []
|
213
|
-
|
214
|
-
rubygems_version: 2.6.14.4
|
245
|
+
rubygems_version: 3.1.4
|
215
246
|
signing_key:
|
216
247
|
specification_version: 4
|
217
248
|
summary: Data transformations inspired by Cambria lenses
|