monolens 0.1.0 → 0.2.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.
- checksums.yaml +5 -5
- data/README.md +8 -4
- data/lib/monolens/array/join.rb +13 -0
- data/lib/monolens/{core → array}/map.rb +1 -1
- data/lib/monolens/array.rb +12 -0
- data/lib/monolens/core/mapping.rb +15 -0
- data/lib/monolens/core.rb +4 -4
- data/lib/monolens/lens.rb +7 -0
- data/lib/monolens/object/select.rb +30 -0
- data/lib/monolens/object.rb +6 -0
- data/lib/monolens/str/split.rb +14 -0
- data/lib/monolens/str.rb +12 -6
- data/lib/monolens/version.rb +1 -1
- data/lib/monolens.rb +1 -1
- data/spec/monolens/array/test_compact.rb +15 -0
- data/spec/monolens/array/test_join.rb +27 -0
- data/spec/monolens/array/test_map.rb +13 -0
- data/spec/monolens/core/test_mapping.rb +51 -0
- data/spec/monolens/object/test_select.rb +73 -0
- data/spec/monolens/skip/test_null.rb +2 -2
- data/spec/monolens/str/test_downcase.rb +13 -0
- data/spec/monolens/str/test_split.rb +39 -0
- data/spec/monolens/str/test_strip.rb +13 -0
- data/spec/monolens/str/test_upcase.rb +13 -0
- data/spec/test_readme.rb +1 -1
- metadata +18 -5
- data/spec/monolens/core/test_map.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 704980b0a35ef47c4ea022a0b2bf39922966a11d
|
4
|
+
data.tar.gz: 0a032437e56dbd4d2214ba7b435120ceceb62709
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a580e3564f5bd208273e16c0c1da4c261917d371e0e6236bab873920b6a2372b7f36e5a085654f8f2ff79490f762cfeb68a8d38a24265d8cd4da5e983389f6e
|
7
|
+
data.tar.gz: '0229785824434dd14c87581f0060a784b623e3154b514bea8548d7cce94bb35563ceb6fdbc45146a883c4ca476c1c329b9adbd6a329ab1382f197377709170a6'
|
data/README.md
CHANGED
@@ -37,13 +37,13 @@ The following monolens file, say `lens.yml`
|
|
37
37
|
---
|
38
38
|
version: 1.0
|
39
39
|
lenses:
|
40
|
-
- map:
|
41
|
-
- object.transform
|
40
|
+
- array.map:
|
41
|
+
- object.transform:
|
42
42
|
status:
|
43
43
|
- str.upcase
|
44
44
|
body:
|
45
45
|
- str.strip
|
46
|
-
- object.rename
|
46
|
+
- object.rename:
|
47
47
|
body: description
|
48
48
|
```
|
49
49
|
|
@@ -76,10 +76,11 @@ result = lens.call(input)
|
|
76
76
|
## Available lenses
|
77
77
|
|
78
78
|
```
|
79
|
-
core.map - Apply a lens to each member of an Array
|
80
79
|
core.chain - Applies a chain of lenses to an input value
|
80
|
+
core.mapping - Converts the input value via a key:value mapping
|
81
81
|
|
82
82
|
str.strip - Remove leading and trailing spaces of an input string
|
83
|
+
str.split - Splits the input string as an array
|
83
84
|
str.downcase - Converts the input string to lowercase
|
84
85
|
str.upcase - Converts the input string to uppercase
|
85
86
|
|
@@ -89,11 +90,14 @@ object.rename - Rename some keys of the input object
|
|
89
90
|
object.transform - Applies specific lenses to specific values of the input object
|
90
91
|
object.keys - Applies a lens to all keys of the input object
|
91
92
|
object.values - Applies a lens to all values of the input object
|
93
|
+
object.select - Builds an object by selecting key/values from the input object
|
92
94
|
|
93
95
|
coerce.date - Coerces the input value to a date
|
94
96
|
coerce.datetime - Coerces the input value to a datetime
|
95
97
|
|
96
98
|
array.compact - Removes null from the input array
|
99
|
+
array.join - Joins values of the input array as a string
|
100
|
+
array.map - Apply a lens to each member of an Array
|
97
101
|
```
|
98
102
|
|
99
103
|
## Public API
|
data/lib/monolens/array.rb
CHANGED
@@ -5,7 +5,19 @@ module Monolens
|
|
5
5
|
end
|
6
6
|
module_function :compact
|
7
7
|
|
8
|
+
def join(options = {})
|
9
|
+
Join.new(options)
|
10
|
+
end
|
11
|
+
module_function :join
|
12
|
+
|
13
|
+
def map(lens)
|
14
|
+
Map.new(lens)
|
15
|
+
end
|
16
|
+
module_function :map
|
17
|
+
|
8
18
|
Monolens.define_namespace 'array', self
|
9
19
|
end
|
10
20
|
end
|
11
21
|
require_relative 'array/compact'
|
22
|
+
require_relative 'array/join'
|
23
|
+
require_relative 'array/map'
|
data/lib/monolens/core.rb
CHANGED
@@ -5,13 +5,13 @@ module Monolens
|
|
5
5
|
end
|
6
6
|
module_function :chain
|
7
7
|
|
8
|
-
def
|
9
|
-
|
8
|
+
def mapping(options)
|
9
|
+
Mapping.new(options)
|
10
10
|
end
|
11
|
-
module_function :
|
11
|
+
module_function :mapping
|
12
12
|
|
13
13
|
Monolens.define_namespace 'core', self
|
14
14
|
end
|
15
15
|
end
|
16
16
|
require_relative 'core/chain'
|
17
|
-
require_relative 'core/
|
17
|
+
require_relative 'core/mapping'
|
data/lib/monolens/lens.rb
CHANGED
@@ -12,11 +12,18 @@ module Monolens
|
|
12
12
|
[ attr, arg[attr] ]
|
13
13
|
elsif arg.key?(attr_s = attr.to_s)
|
14
14
|
[ attr_s, arg[attr_s] ]
|
15
|
+
elsif arg.key?(attr_sym = attr.to_sym)
|
16
|
+
[ attr_sym, arg[attr_sym] ]
|
15
17
|
else
|
16
18
|
[ attr, nil ]
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
22
|
+
def option(name, default = nil)
|
23
|
+
_, option = fetch_on(name, options)
|
24
|
+
option.nil? ? default : option
|
25
|
+
end
|
26
|
+
|
20
27
|
def is_string!(arg)
|
21
28
|
return if arg.is_a?(::String)
|
22
29
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Monolens
|
2
|
+
module Object
|
3
|
+
class Select
|
4
|
+
include Lens
|
5
|
+
|
6
|
+
def initialize(selection)
|
7
|
+
super({})
|
8
|
+
@selection = selection
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(arg, *rest)
|
12
|
+
is_hash!(arg)
|
13
|
+
|
14
|
+
result = {}
|
15
|
+
@selection.each_pair do |new_attr, selector|
|
16
|
+
is_array = selector.is_a?(::Array)
|
17
|
+
is_symbol = false
|
18
|
+
values = Array(selector).map do |old_attr|
|
19
|
+
actual, fetched = fetch_on(old_attr, arg)
|
20
|
+
is_symbol ||= actual.is_a?(Symbol)
|
21
|
+
fetched
|
22
|
+
end
|
23
|
+
new_attr = is_symbol ? new_attr.to_sym : new_attr.to_s
|
24
|
+
result[new_attr] = is_array ? values : values.first
|
25
|
+
end
|
26
|
+
result
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/monolens/object.rb
CHANGED
@@ -20,6 +20,11 @@ module Monolens
|
|
20
20
|
end
|
21
21
|
module_function :values
|
22
22
|
|
23
|
+
def select(lens)
|
24
|
+
Select.new(lens)
|
25
|
+
end
|
26
|
+
module_function :select
|
27
|
+
|
23
28
|
Monolens.define_namespace 'object', self
|
24
29
|
end
|
25
30
|
end
|
@@ -27,3 +32,4 @@ require_relative 'object/rename'
|
|
27
32
|
require_relative 'object/transform'
|
28
33
|
require_relative 'object/keys'
|
29
34
|
require_relative 'object/values'
|
35
|
+
require_relative 'object/select'
|
data/lib/monolens/str.rb
CHANGED
@@ -1,23 +1,29 @@
|
|
1
1
|
module Monolens
|
2
2
|
module Str
|
3
|
+
def downcase(options = {})
|
4
|
+
Downcase.new(options)
|
5
|
+
end
|
6
|
+
module_function :downcase
|
7
|
+
|
3
8
|
def strip(options = {})
|
4
9
|
Strip.new(options)
|
5
10
|
end
|
6
11
|
module_function :strip
|
7
12
|
|
13
|
+
def split(options = {})
|
14
|
+
Split.new(options)
|
15
|
+
end
|
16
|
+
module_function :split
|
17
|
+
|
8
18
|
def upcase(options = {})
|
9
19
|
Upcase.new(options)
|
10
20
|
end
|
11
21
|
module_function :upcase
|
12
22
|
|
13
|
-
def downcase(options = {})
|
14
|
-
Downcase.new(options)
|
15
|
-
end
|
16
|
-
module_function :downcase
|
17
|
-
|
18
23
|
Monolens.define_namespace 'str', self
|
19
24
|
end
|
20
25
|
end
|
26
|
+
require_relative 'str/downcase'
|
21
27
|
require_relative 'str/strip'
|
28
|
+
require_relative 'str/split'
|
22
29
|
require_relative 'str/upcase'
|
23
|
-
require_relative 'str/downcase'
|
data/lib/monolens/version.rb
CHANGED
data/lib/monolens.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'array.compact' do
|
4
|
+
subject do
|
5
|
+
Monolens.lens('array.compact')
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'removes nils' do
|
9
|
+
expect(subject.call([nil, 'notnil'])).to eql(['notnil'])
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'supports empty arrays' do
|
13
|
+
expect(subject.call([])).to eql([])
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'array.join' do
|
4
|
+
context 'when used without options' do
|
5
|
+
subject do
|
6
|
+
Monolens.lens('array.join')
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'joins values with spaces' do
|
10
|
+
expect(subject.call(['hello', 'world'])).to eql('hello world')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'supports empty arrays' do
|
14
|
+
expect(subject.call([])).to eql('')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when specifying the separator' do
|
19
|
+
subject do
|
20
|
+
Monolens.lens('array.join' => { separator: ', ' })
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'joins values with it' do
|
24
|
+
expect(subject.call(['hello', 'world'])).to eql('hello, world')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'array.map' do
|
4
|
+
subject do
|
5
|
+
Monolens.lens('array.map' => 'str.upcase')
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'joins values with spaces' do
|
9
|
+
input = ['hello', 'world']
|
10
|
+
expected = ['HELLO', 'WORLD']
|
11
|
+
expect(subject.call(input)).to eql(expected)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'core.mapping' do
|
4
|
+
let(:mapping) do
|
5
|
+
{ 'values' => { 'todo' => 'open' }}
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'with default options' do
|
9
|
+
subject do
|
10
|
+
Monolens.lens('core.mapping' => mapping)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'replaces the value by its mapped' do
|
14
|
+
expect(subject.call('todo')).to eql('open')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'returns nil if not found' do
|
18
|
+
expect(subject.call('nosuchone')).to eql(nil)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'specifying a default value' do
|
23
|
+
subject do
|
24
|
+
Monolens.lens('core.mapping' => mapping.merge('default' => 'foo'))
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'replaces the value by its mapped' do
|
28
|
+
expect(subject.call('todo')).to eql('open')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns the default if not found' do
|
32
|
+
expect(subject.call('nosuchone')).to eql('foo')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'lets raise if not found' do
|
37
|
+
subject do
|
38
|
+
Monolens.lens('core.mapping' => mapping.merge('fail_if_missing' => true))
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'replaces the value by its mapped' do
|
42
|
+
expect(subject.call('todo')).to eql('open')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'raises if not found' do
|
46
|
+
expect {
|
47
|
+
subject.call('nosuchone')
|
48
|
+
}.to raise_error(Monolens::LensError)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'object.select' do
|
4
|
+
context 'when using symbols in the definition' do
|
5
|
+
subject do
|
6
|
+
Monolens.lens('object.select' => {
|
7
|
+
name: [:firstname, :lastname],
|
8
|
+
status: :priority
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'works as expected' do
|
13
|
+
input = {
|
14
|
+
firstname: 'Bernard',
|
15
|
+
lastname: 'Lambeau',
|
16
|
+
priority: 12
|
17
|
+
}
|
18
|
+
expected = {
|
19
|
+
name: ['Bernard', 'Lambeau'],
|
20
|
+
status: 12
|
21
|
+
}
|
22
|
+
expect(subject.call(input)).to eql(expected)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'works as with Strings' do
|
26
|
+
input = {
|
27
|
+
'firstname' => 'Bernard',
|
28
|
+
'lastname' => 'Lambeau',
|
29
|
+
'priority' => 12
|
30
|
+
}
|
31
|
+
expected = {
|
32
|
+
'name' => ['Bernard', 'Lambeau'],
|
33
|
+
'status' => 12
|
34
|
+
}
|
35
|
+
expect(subject.call(input)).to eql(expected)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when using strings in the definition' do
|
40
|
+
subject do
|
41
|
+
Monolens.lens('object.select' => {
|
42
|
+
'name' => ['firstname', 'lastname'],
|
43
|
+
'status' => 'priority'
|
44
|
+
})
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'works as expected with Symbols' do
|
48
|
+
input = {
|
49
|
+
firstname: 'Bernard',
|
50
|
+
lastname: 'Lambeau',
|
51
|
+
priority: 12
|
52
|
+
}
|
53
|
+
expected = {
|
54
|
+
name: ['Bernard', 'Lambeau'],
|
55
|
+
status: 12
|
56
|
+
}
|
57
|
+
expect(subject.call(input)).to eql(expected)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'works with Strings' do
|
61
|
+
input = {
|
62
|
+
'firstname' => 'Bernard',
|
63
|
+
'lastname' => 'Lambeau',
|
64
|
+
'priority' => 12
|
65
|
+
}
|
66
|
+
expected = {
|
67
|
+
'name' => ['Bernard', 'Lambeau'],
|
68
|
+
'status' => 12
|
69
|
+
}
|
70
|
+
expect(subject.call(input)).to eql(expected)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -17,7 +17,7 @@ describe Monolens, 'skip.null' do
|
|
17
17
|
|
18
18
|
context 'when used in a Map' do
|
19
19
|
subject do
|
20
|
-
Monolens.lens('map' => ['skip.null', 'str.upcase'])
|
20
|
+
Monolens.lens('array.map' => ['skip.null', 'str.upcase'])
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'maps nils' do
|
@@ -27,7 +27,7 @@ describe Monolens, 'skip.null' do
|
|
27
27
|
|
28
28
|
context 'when used in a Map, but we want no nils' do
|
29
29
|
subject do
|
30
|
-
Monolens.lens(['array.compact', { 'map' => ['skip.null', 'str.upcase'] }])
|
30
|
+
Monolens.lens(['array.compact', { 'array.map' => ['skip.null', 'str.upcase'] }])
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'works' do
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'str.split' do
|
4
|
+
context 'without options' do
|
5
|
+
subject do
|
6
|
+
Monolens.lens('str.split')
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'splits a string as an array using space separator' do
|
10
|
+
input = 'foo bar'
|
11
|
+
expected = ['foo', 'bar']
|
12
|
+
expect(subject.call(input)).to eql(expected)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'is greedy on spaces and splits on carriage returns and tabs' do
|
16
|
+
input = "foo bar\nbaz\tboz"
|
17
|
+
expected = ['foo', 'bar', 'baz', 'boz']
|
18
|
+
expect(subject.call(input)).to eql(expected)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when specifying the separator' do
|
23
|
+
subject do
|
24
|
+
Monolens.lens('str.split' => { separator: ',' })
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'uses it' do
|
28
|
+
input = 'foo,bar'
|
29
|
+
expected = ['foo', 'bar']
|
30
|
+
expect(subject.call(input)).to eql(expected)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'does not make whitespace magic' do
|
34
|
+
input = "foo, bar"
|
35
|
+
expected = ['foo', ' bar']
|
36
|
+
expect(subject.call(input)).to eql(expected)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/test_readme.rb
CHANGED
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.
|
4
|
+
version: 0.2.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-
|
11
|
+
date: 2022-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -65,38 +65,50 @@ files:
|
|
65
65
|
- lib/monolens.rb
|
66
66
|
- lib/monolens/array.rb
|
67
67
|
- lib/monolens/array/compact.rb
|
68
|
+
- lib/monolens/array/join.rb
|
69
|
+
- lib/monolens/array/map.rb
|
68
70
|
- lib/monolens/coerce.rb
|
69
71
|
- lib/monolens/coerce/date.rb
|
70
72
|
- lib/monolens/coerce/date_time.rb
|
71
73
|
- lib/monolens/core.rb
|
72
74
|
- lib/monolens/core/chain.rb
|
73
|
-
- lib/monolens/core/
|
75
|
+
- lib/monolens/core/mapping.rb
|
74
76
|
- lib/monolens/error.rb
|
75
77
|
- lib/monolens/file.rb
|
76
78
|
- lib/monolens/lens.rb
|
77
79
|
- lib/monolens/object.rb
|
78
80
|
- lib/monolens/object/keys.rb
|
79
81
|
- lib/monolens/object/rename.rb
|
82
|
+
- lib/monolens/object/select.rb
|
80
83
|
- lib/monolens/object/transform.rb
|
81
84
|
- lib/monolens/object/values.rb
|
82
85
|
- lib/monolens/skip.rb
|
83
86
|
- lib/monolens/skip/null.rb
|
84
87
|
- lib/monolens/str.rb
|
85
88
|
- lib/monolens/str/downcase.rb
|
89
|
+
- lib/monolens/str/split.rb
|
86
90
|
- lib/monolens/str/strip.rb
|
87
91
|
- lib/monolens/str/upcase.rb
|
88
92
|
- lib/monolens/version.rb
|
89
93
|
- spec/fixtures/coerce.yml
|
90
94
|
- spec/fixtures/simple.yml
|
91
95
|
- spec/fixtures/transform.yml
|
96
|
+
- spec/monolens/array/test_compact.rb
|
97
|
+
- spec/monolens/array/test_join.rb
|
98
|
+
- spec/monolens/array/test_map.rb
|
92
99
|
- spec/monolens/coerce/test_date.rb
|
93
100
|
- spec/monolens/coerce/test_datetime.rb
|
94
|
-
- spec/monolens/core/
|
101
|
+
- spec/monolens/core/test_mapping.rb
|
95
102
|
- spec/monolens/object/test_keys.rb
|
96
103
|
- spec/monolens/object/test_rename.rb
|
104
|
+
- spec/monolens/object/test_select.rb
|
97
105
|
- spec/monolens/object/test_transform.rb
|
98
106
|
- spec/monolens/object/test_values.rb
|
99
107
|
- spec/monolens/skip/test_null.rb
|
108
|
+
- spec/monolens/str/test_downcase.rb
|
109
|
+
- spec/monolens/str/test_split.rb
|
110
|
+
- spec/monolens/str/test_strip.rb
|
111
|
+
- spec/monolens/str/test_upcase.rb
|
100
112
|
- spec/monolens/test_lens.rb
|
101
113
|
- spec/spec_helper.rb
|
102
114
|
- spec/test_monolens.rb
|
@@ -122,7 +134,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
134
|
- !ruby/object:Gem::Version
|
123
135
|
version: '0'
|
124
136
|
requirements: []
|
125
|
-
|
137
|
+
rubyforge_project:
|
138
|
+
rubygems_version: 2.6.14.4
|
126
139
|
signing_key:
|
127
140
|
specification_version: 4
|
128
141
|
summary: Data transformations inspired by Cambria lenses
|