monolens 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/monolens/array/compact.rb +2 -2
  3. data/lib/monolens/array/join.rb +2 -2
  4. data/lib/monolens/array/map.rb +45 -6
  5. data/lib/monolens/array.rb +2 -2
  6. data/lib/monolens/coerce/date.rb +20 -6
  7. data/lib/monolens/coerce/date_time.rb +20 -6
  8. data/lib/monolens/coerce/string.rb +13 -0
  9. data/lib/monolens/coerce.rb +6 -3
  10. data/lib/monolens/core/chain.rb +2 -2
  11. data/lib/monolens/core/mapping.rb +2 -2
  12. data/lib/monolens/error.rb +9 -2
  13. data/lib/monolens/file.rb +2 -7
  14. data/lib/monolens/lens/fetch_support.rb +21 -0
  15. data/lib/monolens/lens/location.rb +17 -0
  16. data/lib/monolens/lens/options.rb +41 -0
  17. data/lib/monolens/lens.rb +39 -23
  18. data/lib/monolens/object/keys.rb +8 -10
  19. data/lib/monolens/object/rename.rb +3 -3
  20. data/lib/monolens/object/select.rb +34 -16
  21. data/lib/monolens/object/transform.rb +34 -12
  22. data/lib/monolens/object/values.rb +34 -10
  23. data/lib/monolens/skip/null.rb +1 -1
  24. data/lib/monolens/str/downcase.rb +2 -2
  25. data/lib/monolens/str/split.rb +2 -2
  26. data/lib/monolens/str/strip.rb +3 -1
  27. data/lib/monolens/str/upcase.rb +2 -2
  28. data/lib/monolens/version.rb +1 -1
  29. data/spec/fixtures/coerce.yml +3 -2
  30. data/spec/fixtures/transform.yml +5 -4
  31. data/spec/monolens/array/test_map.rb +89 -6
  32. data/spec/monolens/coerce/test_date.rb +29 -4
  33. data/spec/monolens/coerce/test_datetime.rb +29 -4
  34. data/spec/monolens/coerce/test_string.rb +15 -0
  35. data/spec/monolens/core/test_mapping.rb +25 -0
  36. data/spec/monolens/lens/test_options.rb +73 -0
  37. data/spec/monolens/object/test_keys.rb +54 -22
  38. data/spec/monolens/object/test_rename.rb +1 -1
  39. data/spec/monolens/object/test_select.rb +109 -4
  40. data/spec/monolens/object/test_transform.rb +93 -6
  41. data/spec/monolens/object/test_values.rb +110 -12
  42. data/spec/monolens/test_error_traceability.rb +60 -0
  43. data/spec/monolens/test_lens.rb +1 -1
  44. data/spec/test_readme.rb +7 -5
  45. metadata +9 -2
@@ -1,15 +1,102 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Monolens, 'object.transform' do
4
- subject do
5
- Monolens.lens('object.transform' => { firstname: 'str.upcase' })
4
+ context 'with default options' do
5
+ subject do
6
+ Monolens.lens('object.transform' => {
7
+ defn: { firstname: 'str.upcase' }
8
+ })
9
+ end
10
+
11
+ it 'works as expected' do
12
+ expect(subject.call(firstname: 'Bernard')).to eql(firstname: 'BERNARD')
13
+ end
14
+
15
+ it 'works as expected on an object with String keys' do
16
+ expect(subject.call('firstname' => 'Bernard')).to eql('firstname' => 'BERNARD')
17
+ end
18
+
19
+ it 'raises an error if input object does not have a key' do
20
+ expect {
21
+ subject.call(lastname: 'Lambeau')
22
+ }.to raise_error(Monolens::LensError, /firstname/)
23
+ end
24
+ end
25
+
26
+ context 'with on_missing: skip' do
27
+ subject do
28
+ Monolens.lens('object.transform' => {
29
+ on_missing: :skip,
30
+ defn: { firstname: 'str.upcase' }
31
+ })
32
+ end
33
+
34
+ it 'works as expected' do
35
+ expect(subject.call(firstname: 'Bernard')).to eql(firstname: 'BERNARD')
36
+ end
37
+
38
+ it 'skpis if missing' do
39
+ expect(subject.call(lastname: 'Lambeau')).to eql(lastname: 'Lambeau')
40
+ end
6
41
  end
7
42
 
8
- it 'works as expected' do
9
- expect(subject.call(firstname: 'Bernard')).to eql(firstname: 'BERNARD')
43
+ context 'with on_missing: null' do
44
+ subject do
45
+ Monolens.lens('object.transform' => {
46
+ on_missing: :null,
47
+ defn: { firstname: 'str.upcase' }
48
+ })
49
+ end
50
+
51
+ it 'works as expected' do
52
+ expect(subject.call(firstname: 'Bernard')).to eql(firstname: 'BERNARD')
53
+ end
54
+
55
+ it 'skpis if missing' do
56
+ expect(subject.call(lastname: 'Lambeau')).to eql(firstname: nil, lastname: 'Lambeau')
57
+ end
10
58
  end
11
59
 
12
- it 'works as expected on an object with String keys' do
13
- expect(subject.call('firstname' => 'Bernard')).to eql('firstname' => 'BERNARD')
60
+ describe 'error traceability' do
61
+ let(:lens) do
62
+ Monolens.lens({
63
+ 'array.map' => {
64
+ :lenses => {
65
+ 'object.transform' => {
66
+ defn: { firstname: 'str.upcase' }
67
+ }
68
+ }
69
+ }
70
+ })
71
+ end
72
+
73
+ subject do
74
+ lens.call(input)
75
+ nil
76
+ rescue Monolens::LensError => ex
77
+ ex
78
+ end
79
+
80
+ context 'when missing key' do
81
+ let(:input) do
82
+ [{}]
83
+ end
84
+
85
+ it 'correctly updates the location' do
86
+ expect(subject.location).to eql([0])
87
+ end
88
+ end
89
+
90
+ context 'when an error down the line' do
91
+ let(:input) do
92
+ [{
93
+ firstname: nil
94
+ }]
95
+ end
96
+
97
+ it 'correctly updates the location' do
98
+ expect(subject.location).to eql([0, :firstname])
99
+ end
100
+ end
14
101
  end
15
102
  end
@@ -1,19 +1,117 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Monolens, 'object.values' do
4
- subject do
5
- Monolens.lens('object.values' => ['str.upcase'])
4
+ context 'with default options' do
5
+ subject do
6
+ Monolens.lens('object.values' => ['str.upcase'])
7
+ end
8
+
9
+ it 'works as expected' do
10
+ input = {
11
+ firstname: 'Bernard',
12
+ lastname: 'Lambeau'
13
+ }
14
+ expected = {
15
+ firstname: 'BERNARD',
16
+ lastname: 'LAMBEAU'
17
+ }
18
+ expect(subject.call(input)).to eql(expected)
19
+ end
20
+
21
+ it 'raises an error on any problem' do
22
+ input = {
23
+ firstname: nil,
24
+ lastname: 'Lambeau'
25
+ }
26
+ expect {
27
+ subject.call(input)
28
+ }.to raise_error(Monolens::LensError)
29
+ end
30
+ end
31
+
32
+ context 'with on_error: skip' do
33
+ subject do
34
+ Monolens.lens('object.values' => {
35
+ 'on_error' => 'skip',
36
+ 'lenses' => ['str.upcase']
37
+ })
38
+ end
39
+
40
+ it 'skips key/value when an error occurs' do
41
+ input = {
42
+ firstname: nil,
43
+ lastname: 'Lambeau'
44
+ }
45
+ expected = {
46
+ lastname: 'LAMBEAU'
47
+ }
48
+ expect(subject.call(input)).to eql(expected)
49
+ end
50
+ end
51
+
52
+ context 'with on_error: null' do
53
+ subject do
54
+ Monolens.lens('object.values' => {
55
+ 'on_error' => 'null',
56
+ 'lenses' => ['str.upcase']
57
+ })
58
+ end
59
+
60
+ it 'uses nil as value' do
61
+ input = {
62
+ firstname: 12,
63
+ lastname: 'Lambeau'
64
+ }
65
+ expected = {
66
+ firstname: nil,
67
+ lastname: 'LAMBEAU'
68
+ }
69
+ expect(subject.call(input)).to eql(expected)
70
+ end
71
+ end
72
+
73
+ context 'with on_error: keep' do
74
+ subject do
75
+ Monolens.lens('object.values' => {
76
+ 'on_error' => 'keep',
77
+ 'lenses' => ['str.upcase']
78
+ })
79
+ end
80
+
81
+ it 'uses nil as value' do
82
+ input = {
83
+ firstname: 12,
84
+ lastname: 'Lambeau'
85
+ }
86
+ expected = {
87
+ firstname: 12,
88
+ lastname: 'LAMBEAU'
89
+ }
90
+ expect(subject.call(input)).to eql(expected)
91
+ end
6
92
  end
7
93
 
8
- it 'works as expected' do
9
- input = {
10
- firstname: 'Bernard',
11
- lastname: 'Lambeau'
12
- }
13
- expected = {
14
- firstname: 'BERNARD',
15
- lastname: 'LAMBEAU'
16
- }
17
- expect(subject.call(input)).to eql(expected)
94
+ describe 'error traceability' do
95
+ let(:lens) do
96
+ Monolens.lens('object.values' => ['str.upcase'])
97
+ end
98
+
99
+ subject do
100
+ lens.call(input)
101
+ nil
102
+ rescue Monolens::LensError => ex
103
+ ex
104
+ end
105
+
106
+ let(:input) do
107
+ {
108
+ 'firstname' => 'Bernard',
109
+ 'lastname' => nil
110
+ }
111
+ end
112
+
113
+ it 'correctly updates the location' do
114
+ expect(subject.location).to eql(['lastname'])
115
+ end
18
116
  end
19
117
  end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe Monolens, 'error traceability' do
4
+ context 'on a leaf monolens' do
5
+ let(:lens) do
6
+ Monolens.lens('str.upcase')
7
+ end
8
+
9
+ subject do
10
+ begin
11
+ lens.call(nil)
12
+ rescue => ex
13
+ ex
14
+ end
15
+ end
16
+
17
+ it 'works as expected' do
18
+ expect(subject).to be_a(Monolens::LensError)
19
+ expect(subject.location).to eql([])
20
+ end
21
+ end
22
+
23
+ context 'on array.map' do
24
+ let(:lens) do
25
+ Monolens.lens('array.map' => 'str.upcase')
26
+ end
27
+
28
+ subject do
29
+ begin
30
+ lens.call(['foo', nil])
31
+ rescue => ex
32
+ ex
33
+ end
34
+ end
35
+
36
+ it 'works as expected' do
37
+ expect(subject).to be_a(Monolens::LensError)
38
+ expect(subject.location).to eql([1])
39
+ end
40
+ end
41
+
42
+ context 'on array.map => object.values' do
43
+ let(:lens) do
44
+ Monolens.lens('array.map' => { lenses: { 'object.values' => 'str.upcase' } })
45
+ end
46
+
47
+ subject do
48
+ begin
49
+ lens.call([{ hello: 'foo' }, { hello: nil }])
50
+ rescue Monolens::LensError => ex
51
+ ex
52
+ end
53
+ end
54
+
55
+ it 'works as expected' do
56
+ expect(subject).to be_a(Monolens::LensError)
57
+ expect(subject.location).to eql([1, :hello])
58
+ end
59
+ end
60
+ end
@@ -16,7 +16,7 @@ describe Monolens, '.lens' do
16
16
  it 'preserves options' do
17
17
  got = Monolens.lens(:"coerce.date" => { formats: ['%Y'] })
18
18
  expect(got).to be_a(Monolens::Coerce::Date)
19
- expect(got.options).to eql({ formats: ['%Y'] })
19
+ expect(got.options.to_h).to eql({ formats: ['%Y'] })
20
20
  end
21
21
 
22
22
  it 'allows using an Array, factors a Chain with coercion recursion' do
data/spec/test_readme.rb CHANGED
@@ -23,12 +23,14 @@ describe "What's said in README" do
23
23
  lenses:
24
24
  - array.map:
25
25
  - object.transform:
26
- status:
27
- - str.upcase
28
- body:
29
- - str.strip
26
+ defn:
27
+ status:
28
+ - str.upcase
29
+ body:
30
+ - str.strip
30
31
  - object.rename:
31
- body: description
32
+ defn:
33
+ body: description
32
34
  YML
33
35
  }
34
36
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monolens
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
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-05-05 00:00:00.000000000 Z
11
+ date: 2022-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -70,12 +70,16 @@ files:
70
70
  - lib/monolens/coerce.rb
71
71
  - lib/monolens/coerce/date.rb
72
72
  - lib/monolens/coerce/date_time.rb
73
+ - lib/monolens/coerce/string.rb
73
74
  - lib/monolens/core.rb
74
75
  - lib/monolens/core/chain.rb
75
76
  - lib/monolens/core/mapping.rb
76
77
  - lib/monolens/error.rb
77
78
  - lib/monolens/file.rb
78
79
  - lib/monolens/lens.rb
80
+ - lib/monolens/lens/fetch_support.rb
81
+ - lib/monolens/lens/location.rb
82
+ - lib/monolens/lens/options.rb
79
83
  - lib/monolens/object.rb
80
84
  - lib/monolens/object/keys.rb
81
85
  - lib/monolens/object/rename.rb
@@ -98,7 +102,9 @@ files:
98
102
  - spec/monolens/array/test_map.rb
99
103
  - spec/monolens/coerce/test_date.rb
100
104
  - spec/monolens/coerce/test_datetime.rb
105
+ - spec/monolens/coerce/test_string.rb
101
106
  - spec/monolens/core/test_mapping.rb
107
+ - spec/monolens/lens/test_options.rb
102
108
  - spec/monolens/object/test_keys.rb
103
109
  - spec/monolens/object/test_rename.rb
104
110
  - spec/monolens/object/test_select.rb
@@ -109,6 +115,7 @@ files:
109
115
  - spec/monolens/str/test_split.rb
110
116
  - spec/monolens/str/test_strip.rb
111
117
  - spec/monolens/str/test_upcase.rb
118
+ - spec/monolens/test_error_traceability.rb
112
119
  - spec/monolens/test_lens.rb
113
120
  - spec/spec_helper.rb
114
121
  - spec/test_monolens.rb