monolens 0.6.0 → 0.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 836c097ee70c9517d08ce544cbd1cd9b600a846b
4
- data.tar.gz: 1af2f7a32e00bef2e3d69a0451f94c367e83d5d6
2
+ SHA256:
3
+ metadata.gz: aea34c867c10c00a01b0f7d986d7aaa76df80048d828d9ebd7083d9aa35853e9
4
+ data.tar.gz: cb611d504ff32059dd57736c0964acade1983b7e962d69504f1873fb7100a4d7
5
5
  SHA512:
6
- metadata.gz: dd6e356d995c5e1d28b9f46491abec5a95ccaa8f1efaa463600dbe4b146a97ad5ef56ecb19b69be000c24f91a4bb74afde5cbf0ce15ebcda8fd9b7b262e72e53
7
- data.tar.gz: e78d2ce7b2cfc47d83bd53ae179b1ae29d24c9edc78a131b1d2b085ab6a1d35cf2cdb3edccca256c58a937510b7d0de4440847a15b56e2d288ff2e5e9b0140a9
6
+ metadata.gz: cbecb6300c62e819c18ae4b4d8926041acb60519cfa8b33aea9e93b9c2826484c479069513e3903547ae13619e06e699b9b8c7e8f766982e97040f195388a214
7
+ data.tar.gz: '079b220b7dacd7ee54f7a3b668351f832b37ee70c2c5a9c17cf21ed6c10324eff2da4f291e0fe75e0a1f59c2932fccbdfa1cbaf66d95e742079869477920149b'
@@ -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
@@ -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
- lens_data, input = read_file(lens), read_input
37
- lens = build_lens(lens_data)
38
- error_handler = ErrorHandler.new
39
- result = lens.call(input, error_handler: error_handler)
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
- unless error_handler.empty?
42
- stderr.puts(error_handler.report)
43
- end
51
+ unless error_handler.empty?
52
+ stderr.puts(error_handler.report)
53
+ end
44
54
 
45
- output_result(result) if result
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(-2)
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
@@ -2,7 +2,7 @@ module Monolens
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 6
5
- TINY = 0
5
+ TINY = 1
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
@@ -0,0 +1,15 @@
1
+ ---
2
+ version: '1.0'
3
+ lenses:
4
+ - array.map:
5
+ lenses:
6
+ - core.literal:
7
+ defn:
8
+ name: $.name
9
+ examples:
10
+ - input:
11
+ - name: Monolens
12
+ - name: Bmg
13
+ output:
14
+ - name: Monolens
15
+ - name: BMG
@@ -0,0 +1,13 @@
1
+ ---
2
+ version: '1.0'
3
+ lenses:
4
+ - str.upcase
5
+ examples:
6
+ - input:
7
+ Monolens
8
+ output:
9
+ Monolens
10
+ - input:
11
+ Monolens
12
+ output:
13
+ MONOLENS
@@ -0,0 +1,9 @@
1
+ ---
2
+ version: '1.0'
3
+ lenses:
4
+ - str.upcase
5
+ examples:
6
+ - input:
7
+ Monolens
8
+ output:
9
+ MONOLENS
@@ -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(-2)
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.0
4
+ version: 0.6.1
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-07-08 00:00:00.000000000 Z
11
+ date: 2022-07-15 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
- rubyforge_project:
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