monolens 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|