monolens 0.5.3 → 0.6.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 +4 -4
- data/README.md +51 -85
- data/lib/monolens/command.rb +111 -14
- data/lib/monolens/error.rb +2 -0
- data/lib/monolens/file.rb +6 -0
- data/lib/monolens/jsonpath.rb +76 -0
- data/lib/monolens/lens/options.rb +26 -12
- data/lib/monolens/lens/signature/missing.rb +11 -0
- data/lib/monolens/lens/signature.rb +60 -0
- data/lib/monolens/lens.rb +25 -4
- data/lib/monolens/macros.rb +28 -0
- data/lib/monolens/namespace.rb +11 -0
- data/lib/monolens/registry.rb +77 -0
- data/lib/monolens/{array → stdlib/array}/compact.rb +2 -0
- data/lib/monolens/{array → stdlib/array}/join.rb +4 -0
- data/lib/monolens/{array → stdlib/array}/map.rb +13 -19
- data/lib/monolens/{array.rb → stdlib/array.rb} +8 -6
- data/lib/monolens/{check → stdlib/check}/not_empty.rb +4 -0
- data/lib/monolens/{check.rb → stdlib/check.rb} +4 -2
- data/lib/monolens/{coerce → stdlib/coerce}/date.rb +5 -0
- data/lib/monolens/{coerce → stdlib/coerce}/date_time.rb +6 -1
- data/lib/monolens/{coerce → stdlib/coerce}/integer.rb +4 -0
- data/lib/monolens/{coerce → stdlib/coerce}/string.rb +2 -0
- data/lib/monolens/{coerce.rb → stdlib/coerce.rb} +10 -8
- data/lib/monolens/{core → stdlib/core}/chain.rb +5 -3
- data/lib/monolens/{core → stdlib/core}/dig.rb +5 -0
- data/lib/monolens/stdlib/core/literal.rb +68 -0
- data/lib/monolens/{core → stdlib/core}/mapping.rb +15 -5
- data/lib/monolens/{core.rb → stdlib/core.rb} +10 -8
- data/lib/monolens/stdlib/object/allbut.rb +22 -0
- data/lib/monolens/{object → stdlib/object}/extend.rb +10 -5
- data/lib/monolens/{object → stdlib/object}/keys.rb +4 -0
- data/lib/monolens/stdlib/object/merge.rb +56 -0
- data/lib/monolens/{object → stdlib/object}/rename.rb +5 -1
- data/lib/monolens/{object → stdlib/object}/select.rb +9 -0
- data/lib/monolens/{object → stdlib/object}/transform.rb +8 -3
- data/lib/monolens/{object → stdlib/object}/values.rb +9 -4
- data/lib/monolens/stdlib/object.rb +55 -0
- data/lib/monolens/{skip → stdlib/skip}/null.rb +2 -0
- data/lib/monolens/{skip.rb → stdlib/skip.rb} +4 -2
- data/lib/monolens/{str → stdlib/str}/downcase.rb +2 -0
- data/lib/monolens/{str → stdlib/str}/split.rb +5 -1
- data/lib/monolens/{str → stdlib/str}/strip.rb +2 -0
- data/lib/monolens/{str → stdlib/str}/upcase.rb +2 -0
- data/lib/monolens/{str.rb → stdlib/str.rb} +10 -8
- data/lib/monolens/stdlib.rb +7 -0
- data/lib/monolens/type/any.rb +39 -0
- data/lib/monolens/type/array.rb +27 -0
- data/lib/monolens/type/boolean.rb +17 -0
- data/lib/monolens/type/callback.rb +17 -0
- data/lib/monolens/type/coercible.rb +10 -0
- data/lib/monolens/type/diggable.rb +9 -0
- data/lib/monolens/type/emptyable.rb +9 -0
- data/lib/monolens/type/integer.rb +18 -0
- data/lib/monolens/type/lenses.rb +17 -0
- data/lib/monolens/type/map.rb +30 -0
- data/lib/monolens/type/object.rb +17 -0
- data/lib/monolens/type/responding.rb +25 -0
- data/lib/monolens/type/strategy.rb +56 -0
- data/lib/monolens/type/string.rb +18 -0
- data/lib/monolens/type/symbol.rb +20 -0
- data/lib/monolens/type.rb +33 -0
- data/lib/monolens/version.rb +2 -2
- data/lib/monolens.rb +22 -66
- data/spec/fixtures/macro.yml +13 -0
- data/spec/fixtures/recursive.yml +15 -0
- data/spec/monolens/command/literal.yml +2 -0
- data/spec/monolens/command/literal2.yml +2 -0
- data/spec/monolens/command/upcase.lens.yml +4 -0
- data/spec/monolens/lens/test_options.rb +2 -14
- data/spec/monolens/lens/test_signature.rb +38 -0
- data/spec/monolens/{array → stdlib/array}/test_compact.rb +8 -0
- data/spec/monolens/{array → stdlib/array}/test_join.rb +0 -0
- data/spec/monolens/{array → stdlib/array}/test_map.rb +15 -0
- data/spec/monolens/{check → stdlib/check}/test_not_empty.rb +0 -0
- data/spec/monolens/{coerce → stdlib/coerce}/test_date.rb +0 -0
- data/spec/monolens/{coerce → stdlib/coerce}/test_datetime.rb +1 -1
- data/spec/monolens/{coerce → stdlib/coerce}/test_integer.rb +0 -0
- data/spec/monolens/{coerce → stdlib/coerce}/test_string.rb +0 -0
- data/spec/monolens/{core → stdlib/core}/test_dig.rb +0 -0
- data/spec/monolens/stdlib/core/test_literal.rb +73 -0
- data/spec/monolens/{core → stdlib/core}/test_mapping.rb +37 -1
- data/spec/monolens/stdlib/object/test_allbut.rb +31 -0
- data/spec/monolens/{object → stdlib/object}/test_extend.rb +0 -0
- data/spec/monolens/{object → stdlib/object}/test_keys.rb +0 -0
- data/spec/monolens/stdlib/object/test_merge.rb +133 -0
- data/spec/monolens/{object → stdlib/object}/test_rename.rb +0 -0
- data/spec/monolens/{object → stdlib/object}/test_select.rb +0 -0
- data/spec/monolens/{object → stdlib/object}/test_transform.rb +0 -0
- data/spec/monolens/{object → stdlib/object}/test_values.rb +0 -0
- data/spec/monolens/{skip → stdlib/skip}/test_null.rb +0 -0
- data/spec/monolens/{str → stdlib/str}/test_downcase.rb +0 -0
- data/spec/monolens/{str → stdlib/str}/test_split.rb +0 -0
- data/spec/monolens/{str → stdlib/str}/test_strip.rb +0 -0
- data/spec/monolens/{str → stdlib/str}/test_upcase.rb +0 -0
- data/spec/monolens/test_command.rb +145 -0
- data/spec/monolens/test_error_traceability.rb +1 -1
- data/spec/monolens/test_jsonpath.rb +88 -0
- data/spec/monolens/test_lens.rb +1 -1
- data/spec/test_documentation.rb +52 -0
- data/spec/test_monolens.rb +20 -0
- data/tasks/test.rake +1 -1
- metadata +91 -55
- data/lib/monolens/core/literal.rb +0 -11
- data/lib/monolens/object.rb +0 -41
- data/spec/monolens/core/test_literal.rb +0 -13
@@ -0,0 +1,77 @@
|
|
1
|
+
module Monolens
|
2
|
+
class Registry
|
3
|
+
LENS_NAME_RX = /^[a-z]+\.[a-z][a-zA-Z\-_]+$/
|
4
|
+
|
5
|
+
def initialize(registry = {}, default_namespace = 'core')
|
6
|
+
@registry = registry
|
7
|
+
@default_namespace = default_namespace
|
8
|
+
end
|
9
|
+
|
10
|
+
def define_namespace(name, impl_module)
|
11
|
+
@registry[name] = impl_module
|
12
|
+
end
|
13
|
+
|
14
|
+
def load_file(file, registry = self)
|
15
|
+
load_yaml(::File.read(file), registry)
|
16
|
+
end
|
17
|
+
|
18
|
+
def load_yaml(yaml, registry = self)
|
19
|
+
Monolens::File.new(YAML.safe_load(yaml), registry)
|
20
|
+
end
|
21
|
+
|
22
|
+
def lens(arg, registry = self)
|
23
|
+
case arg
|
24
|
+
when Lens then arg
|
25
|
+
when ::Array then chain(arg, registry)
|
26
|
+
when ::String, ::Symbol then leaf_lens(arg, registry)
|
27
|
+
when ::Hash then hash_lens(arg, registry)
|
28
|
+
else
|
29
|
+
raise Error, "No such lens #{arg} (#{arg.class})"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def fork(default_namespace = 'self')
|
34
|
+
Registry.new(@registry.dup, default_namespace)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def chain(lenses, registry)
|
40
|
+
Core::Chain.new(lenses.map{|l| lens(l) }, registry)
|
41
|
+
end
|
42
|
+
|
43
|
+
def file_lens(arg, registry)
|
44
|
+
File.new(arg, registry)
|
45
|
+
end
|
46
|
+
|
47
|
+
def leaf_lens(arg, registry)
|
48
|
+
namespace_name, lens_name = split_lens_name(arg)
|
49
|
+
factor_lens(namespace_name, lens_name, {}, registry)
|
50
|
+
end
|
51
|
+
|
52
|
+
def hash_lens(arg, registry)
|
53
|
+
return file_lens(arg, registry) if arg['version'] || arg[:version]
|
54
|
+
raise Error, "Invalid lens #{arg}" unless arg.size == 1
|
55
|
+
|
56
|
+
name, options = arg.to_a.first
|
57
|
+
namespace_name, lens_name = split_lens_name(name)
|
58
|
+
factor_lens(namespace_name, lens_name, options, registry)
|
59
|
+
end
|
60
|
+
|
61
|
+
def factor_lens(namespace_name, lens_name, options, registry)
|
62
|
+
if namespace = @registry[namespace_name]
|
63
|
+
namespace.factor_lens(namespace_name, lens_name, options, registry)
|
64
|
+
else
|
65
|
+
raise Error, "No such namespace #{namespace_name}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def split_lens_name(name)
|
70
|
+
if name =~ LENS_NAME_RX
|
71
|
+
name.to_s.split('.')
|
72
|
+
else
|
73
|
+
[@default_namespace, name]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -3,44 +3,38 @@ module Monolens
|
|
3
3
|
class Map
|
4
4
|
include Lens
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
_, ls = fetch_on(:lenses, arg)
|
11
|
-
raise ArgumentError, 'Lenses are required' if ls.nil?
|
12
|
-
[ opts, ls ]
|
13
|
-
else
|
14
|
-
[{}, arg]
|
15
|
-
end
|
16
|
-
super(options)
|
17
|
-
@lenses = Monolens.lens(lenses)
|
18
|
-
end
|
6
|
+
signature(Type::Array, Type::Array, {
|
7
|
+
on_error: [Type::Strategy.error(%w{handler keep fail null skip}), false],
|
8
|
+
lenses: [Type::Lenses, true]
|
9
|
+
})
|
19
10
|
|
20
11
|
def call(arg, world = {})
|
21
|
-
|
12
|
+
is_array!(arg, world)
|
22
13
|
|
14
|
+
lenses = option(:lenses)
|
23
15
|
result = []
|
24
|
-
arg.each_with_index do |
|
16
|
+
arg.each_with_index do |member, i|
|
25
17
|
deeper(world, i) do |w|
|
26
18
|
begin
|
27
|
-
result <<
|
19
|
+
result << lenses.call(member, w)
|
28
20
|
rescue Monolens::LensError => ex
|
29
21
|
strategy = option(:on_error, :fail)
|
30
|
-
handle_error(strategy, ex, result, world)
|
22
|
+
handle_error(strategy, member, ex, result, world)
|
31
23
|
end
|
32
24
|
end
|
33
25
|
end
|
34
26
|
result
|
35
27
|
end
|
36
28
|
|
37
|
-
def handle_error(strategy, ex, result, world)
|
29
|
+
def handle_error(strategy, member, ex, result, world)
|
38
30
|
strategy = strategy.to_sym unless strategy.is_a?(::Array)
|
39
31
|
case strategy
|
40
32
|
when ::Array
|
41
|
-
strategy.each{|s| handle_error(s, ex, result, world) }
|
33
|
+
strategy.each{|s| handle_error(s, member, ex, result, world) }
|
42
34
|
when :handler
|
43
35
|
error_handler!(world).call(ex)
|
36
|
+
when :keep
|
37
|
+
result << member
|
44
38
|
when :fail
|
45
39
|
raise
|
46
40
|
when :null
|
@@ -1,17 +1,19 @@
|
|
1
1
|
module Monolens
|
2
2
|
module Array
|
3
|
-
|
4
|
-
|
3
|
+
extend Namespace
|
4
|
+
|
5
|
+
def compact(options, registry)
|
6
|
+
Compact.new(options, registry)
|
5
7
|
end
|
6
8
|
module_function :compact
|
7
9
|
|
8
|
-
def join(options
|
9
|
-
Join.new(options)
|
10
|
+
def join(options, registry)
|
11
|
+
Join.new(options, registry)
|
10
12
|
end
|
11
13
|
module_function :join
|
12
14
|
|
13
|
-
def map(options)
|
14
|
-
Map.new(options)
|
15
|
+
def map(options, registry)
|
16
|
+
Map.new(options, registry)
|
15
17
|
end
|
16
18
|
module_function :map
|
17
19
|
|
@@ -9,6 +9,11 @@ module Monolens
|
|
9
9
|
nil
|
10
10
|
]
|
11
11
|
|
12
|
+
signature(Type::Coercible.to(Type::String), Type::Date, {
|
13
|
+
parser: [Type::DateTimeParser, false],
|
14
|
+
formats: [Type::Array.of(Type::String), false]
|
15
|
+
})
|
16
|
+
|
12
17
|
def call(arg, world = {})
|
13
18
|
return arg if arg.is_a?(::Date)
|
14
19
|
|
@@ -9,6 +9,11 @@ module Monolens
|
|
9
9
|
nil
|
10
10
|
]
|
11
11
|
|
12
|
+
signature(Type::Coercible.to(Type::String), Type::DateTime, {
|
13
|
+
parser: [Type::DateTimeParser, false],
|
14
|
+
formats: [Type::Array.of(Type::String), false]
|
15
|
+
})
|
16
|
+
|
12
17
|
def call(arg, world = {})
|
13
18
|
return arg if arg.is_a?(::DateTime)
|
14
19
|
|
@@ -16,7 +21,7 @@ module Monolens
|
|
16
21
|
|
17
22
|
date = nil
|
18
23
|
first_error = nil
|
19
|
-
formats =
|
24
|
+
formats = option(:formats, DEFAULT_FORMATS)
|
20
25
|
formats.each do |format|
|
21
26
|
begin
|
22
27
|
return date = strptime(arg, format)
|
@@ -5,10 +5,14 @@ module Monolens
|
|
5
5
|
class Integer
|
6
6
|
include Lens
|
7
7
|
|
8
|
+
signature(Type::Coercible.to(Type::Integer), Type::Integer)
|
9
|
+
|
8
10
|
def call(arg, world = {})
|
9
11
|
Integer(arg)
|
10
12
|
rescue => ex
|
11
13
|
fail!(ex.message, world)
|
14
|
+
rescue ArgumentError => ex
|
15
|
+
fail!(ex.message, world)
|
12
16
|
end
|
13
17
|
end
|
14
18
|
end
|
@@ -1,22 +1,24 @@
|
|
1
1
|
module Monolens
|
2
2
|
module Coerce
|
3
|
-
|
4
|
-
|
3
|
+
extend Namespace
|
4
|
+
|
5
|
+
def date(options, registry)
|
6
|
+
Date.new(options, registry)
|
5
7
|
end
|
6
8
|
module_function :date
|
7
9
|
|
8
|
-
def integer(options
|
9
|
-
Integer.new(options)
|
10
|
+
def integer(options, registry)
|
11
|
+
Integer.new(options, registry)
|
10
12
|
end
|
11
13
|
module_function :integer
|
12
14
|
|
13
|
-
def datetime(options
|
14
|
-
DateTime.new(options)
|
15
|
+
def datetime(options, registry)
|
16
|
+
DateTime.new(options, registry)
|
15
17
|
end
|
16
18
|
module_function :datetime
|
17
19
|
|
18
|
-
def string(options
|
19
|
-
String.new(options)
|
20
|
+
def string(options, registry)
|
21
|
+
String.new(options, registry)
|
20
22
|
end
|
21
23
|
module_function :string
|
22
24
|
|
@@ -3,9 +3,11 @@ module Monolens
|
|
3
3
|
class Chain
|
4
4
|
include Lens
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
signature(Type::Any, Type::Any)
|
7
|
+
|
8
|
+
def initialize(options, registry)
|
9
|
+
super({}, registry)
|
10
|
+
@lenses = options.map{|l| lens(l) }
|
9
11
|
end
|
10
12
|
|
11
13
|
def call(arg, world = {})
|
@@ -3,6 +3,11 @@ module Monolens
|
|
3
3
|
class Dig
|
4
4
|
include Lens
|
5
5
|
|
6
|
+
signature(Type::Diggable, Type::Any, {
|
7
|
+
defn: [Type::Array.of(Type::Any.of(Type::Integer, Type::String)), true],
|
8
|
+
on_missing: [Type::Strategy.missing(%w{fail null}), false]
|
9
|
+
})
|
10
|
+
|
6
11
|
def call(arg, world = {})
|
7
12
|
option(:defn, []).inject(arg) do |memo, part|
|
8
13
|
dig_on(part, memo, world)
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Monolens
|
2
|
+
module Core
|
3
|
+
class Literal
|
4
|
+
include Lens
|
5
|
+
|
6
|
+
signature(Type::Any, Type::Any, {
|
7
|
+
defn: [Type::Any, true],
|
8
|
+
jsonpath: [Type::Object, false]
|
9
|
+
})
|
10
|
+
|
11
|
+
def initialize(options, registry)
|
12
|
+
super(options, registry)
|
13
|
+
@root_symbol = extract_jsonpath_root_symbol
|
14
|
+
@one_rx = Jsonpath.one_detect_rx(@root_symbol)
|
15
|
+
@interpolate_rx = Jsonpath.interpolate_detect_rx(@root_symbol)
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(arg, world = {})
|
19
|
+
instantiate(option(:defn), arg, world)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def instantiate(obj, input, world)
|
25
|
+
case obj
|
26
|
+
when ::Array
|
27
|
+
obj.map {|item|
|
28
|
+
instantiate(item, input, world)
|
29
|
+
}
|
30
|
+
when ::Hash
|
31
|
+
obj.each_with_object({}){|(k,v),memo|
|
32
|
+
memo[k] = instantiate(v, input, world)
|
33
|
+
}
|
34
|
+
when @one_rx
|
35
|
+
Jsonpath.one(obj, input, jsonpath_options(input))
|
36
|
+
when @interpolate_rx
|
37
|
+
Jsonpath.interpolate(obj, input, jsonpath_options(input))
|
38
|
+
else
|
39
|
+
obj
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def jsonpath_options(input)
|
44
|
+
{
|
45
|
+
use_symbols: use_symbols?(input),
|
46
|
+
root_symbol: @root_symbol
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def extract_jsonpath_root_symbol
|
51
|
+
opts = option(:jsonpath, {})
|
52
|
+
_, symbol = fetch_on(:root_symbol, opts, '$')
|
53
|
+
symbol
|
54
|
+
end
|
55
|
+
|
56
|
+
def use_symbols?(input)
|
57
|
+
case input
|
58
|
+
when ::Hash
|
59
|
+
input.keys.any?{|s| s.is_a?(Symbol) }
|
60
|
+
when ::Array
|
61
|
+
input.any?{|x| use_symbols?(x) }
|
62
|
+
else
|
63
|
+
false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -3,8 +3,16 @@ module Monolens
|
|
3
3
|
class Mapping
|
4
4
|
include Lens
|
5
5
|
|
6
|
+
signature(Type::Any, Type::Any, {
|
7
|
+
defn: [Type::Object, false],
|
8
|
+
values: [Type::Object, false], # deprecated
|
9
|
+
default: [Type::Any, false],
|
10
|
+
fallback: [Type::Callback, false],
|
11
|
+
on_missing: [Type::Strategy.missing(%w{default fail fallback keep null}), false]
|
12
|
+
})
|
13
|
+
|
6
14
|
def call(arg, world = {})
|
7
|
-
option(:values, {}).fetch(arg) do
|
15
|
+
option(:defn, option(:values, {})).fetch(arg) do
|
8
16
|
on_missing(arg, world)
|
9
17
|
end
|
10
18
|
end
|
@@ -14,17 +22,19 @@ module Monolens
|
|
14
22
|
def on_missing(arg, world)
|
15
23
|
strategy = option(:on_missing, :fail)
|
16
24
|
case strategy.to_sym
|
17
|
-
when :fail
|
18
|
-
fail!("Unrecognized value `#{arg}`", world)
|
19
25
|
when :default
|
20
26
|
option(:default, nil)
|
21
|
-
when :
|
22
|
-
|
27
|
+
when :fail
|
28
|
+
fail!("Unrecognized value `#{arg}`", world)
|
23
29
|
when :fallback
|
24
30
|
missing_fallback = ->(arg, world) do
|
25
31
|
raise Monolens::Error, "Unexpected missing fallback handler"
|
26
32
|
end
|
27
33
|
option(:fallback, missing_fallback).call(self, arg, world)
|
34
|
+
when :keep
|
35
|
+
arg
|
36
|
+
when :null
|
37
|
+
nil
|
28
38
|
else
|
29
39
|
raise Monolens::Error, "Unexpected missing strategy `#{strategy}`"
|
30
40
|
end
|
@@ -1,22 +1,24 @@
|
|
1
1
|
module Monolens
|
2
2
|
module Core
|
3
|
-
|
4
|
-
|
3
|
+
extend Namespace
|
4
|
+
|
5
|
+
def chain(options, registry)
|
6
|
+
Chain.new(options, registry)
|
5
7
|
end
|
6
8
|
module_function :chain
|
7
9
|
|
8
|
-
def dig(options)
|
9
|
-
Dig.new(options)
|
10
|
+
def dig(options, registry)
|
11
|
+
Dig.new(options, registry)
|
10
12
|
end
|
11
13
|
module_function :dig
|
12
14
|
|
13
|
-
def literal(options)
|
14
|
-
Literal.new(options)
|
15
|
+
def literal(options, registry)
|
16
|
+
Literal.new(options, registry)
|
15
17
|
end
|
16
18
|
module_function :literal
|
17
19
|
|
18
|
-
def mapping(options)
|
19
|
-
Mapping.new(options)
|
20
|
+
def mapping(options, registry)
|
21
|
+
Mapping.new(options, registry)
|
20
22
|
end
|
21
23
|
module_function :mapping
|
22
24
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Monolens
|
2
|
+
module Object
|
3
|
+
class Allbut
|
4
|
+
include Lens
|
5
|
+
|
6
|
+
signature(Type::Object, Type::Object, {
|
7
|
+
defn: [Type::Array.of(Type::Name), false]
|
8
|
+
})
|
9
|
+
|
10
|
+
def call(arg, world = {})
|
11
|
+
is_hash!(arg, world)
|
12
|
+
|
13
|
+
allbut = option(:defn, [])
|
14
|
+
arg.delete_if{|k|
|
15
|
+
allbut.include?(k) || \
|
16
|
+
allbut.include?(k.to_s) || \
|
17
|
+
allbut.include?(k.to_sym)
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -3,11 +3,16 @@ module Monolens
|
|
3
3
|
class Extend
|
4
4
|
include Lens
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
signature(Type::Object, Type::Object, {
|
7
|
+
defn: [Type::Map.of(Type::Name, Type::Lenses), false],
|
8
|
+
on_error: [Type::Strategy.error(%w{fail handler null skip}), false],
|
9
|
+
})
|
10
|
+
|
11
|
+
def initialize(options, registry)
|
12
|
+
super(options, registry)
|
8
13
|
ts = option(:defn, {})
|
9
14
|
ts.each_pair do |k,v|
|
10
|
-
ts[k] =
|
15
|
+
ts[k] = lens(v)
|
11
16
|
end
|
12
17
|
end
|
13
18
|
|
@@ -35,10 +40,10 @@ module Monolens
|
|
35
40
|
case strategy
|
36
41
|
when ::Array
|
37
42
|
strategy.each{|s| handle_error(s, ex, result, attr, world) }
|
38
|
-
when :handler
|
39
|
-
error_handler!(world).call(ex)
|
40
43
|
when :fail
|
41
44
|
raise
|
45
|
+
when :handler
|
46
|
+
error_handler!(world).call(ex)
|
42
47
|
when :null
|
43
48
|
result[attr] = nil
|
44
49
|
when :skip
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Monolens
|
2
|
+
module Object
|
3
|
+
class Merge
|
4
|
+
include Lens
|
5
|
+
|
6
|
+
signature(Type::Object, Type::Object, {
|
7
|
+
priority: [Type::Strategy.priority(%w{input defn}), false],
|
8
|
+
deep: [Type::Boolean, false],
|
9
|
+
defn: [Type::Object, true]
|
10
|
+
})
|
11
|
+
|
12
|
+
def call(input, world = {})
|
13
|
+
is_hash!(input, world)
|
14
|
+
|
15
|
+
v1, v2 = input, option(:defn, {})
|
16
|
+
if deep?
|
17
|
+
deep_merge(v1, v2, world, priority_at_input?)
|
18
|
+
else
|
19
|
+
normal_merge(v1, v2, world, priority_at_input?)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def normal_merge(v1, v2, world, priority_at_input)
|
26
|
+
is_hash!(v1, world)
|
27
|
+
is_hash!(v2, world)
|
28
|
+
|
29
|
+
v1.merge(v2) do |k, v11, v22|
|
30
|
+
priority_at_input? ? v11 : v22
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def deep_merge(v1, v2, world, priority_at_input)
|
35
|
+
case v1
|
36
|
+
when ::Hash
|
37
|
+
is_hash!(v2, world)
|
38
|
+
|
39
|
+
v1.merge(v2) do |k, v11, v22|
|
40
|
+
deep_merge(v11, v22, world, priority_at_input)
|
41
|
+
end
|
42
|
+
else
|
43
|
+
priority_at_input? ? v1 : v2
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def deep?
|
48
|
+
option(:deep, false) == true
|
49
|
+
end
|
50
|
+
|
51
|
+
def priority_at_input?
|
52
|
+
@pati ||= (option(:priority, 'defn').to_s == 'input')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -3,11 +3,15 @@ module Monolens
|
|
3
3
|
class Rename
|
4
4
|
include Lens
|
5
5
|
|
6
|
+
signature(Type::Object, Type::Object, {
|
7
|
+
defn: [Type::Map.of(Type::Name, Type::Name), false],
|
8
|
+
})
|
9
|
+
|
6
10
|
def call(arg, world = {})
|
7
11
|
is_hash!(arg, world)
|
8
12
|
|
9
13
|
dup = arg.dup
|
10
|
-
option(:defn).each_pair do |oldname, newname|
|
14
|
+
option(:defn, {}).each_pair do |oldname, newname|
|
11
15
|
actual_name, value = fetch_on(oldname, arg)
|
12
16
|
newname = actual_name.is_a?(Symbol) ? newname.to_sym : newname.to_s
|
13
17
|
dup.delete(actual_name)
|
@@ -3,6 +3,15 @@ module Monolens
|
|
3
3
|
class Select
|
4
4
|
include Lens
|
5
5
|
|
6
|
+
signature(Type::Object, Type::Object, {
|
7
|
+
strategy: [Type::Strategy.selection(%w{all first}), false],
|
8
|
+
defn: [Type::Any.of(
|
9
|
+
Type::Array.of(Type::Name),
|
10
|
+
Type::Map.of(Type::Name, Type::Any.of(Type::Array.of(Type::Name), Type::Name))
|
11
|
+
), true],
|
12
|
+
on_missing: [Type::Strategy.missing(%w{fail null skip}), false]
|
13
|
+
})
|
14
|
+
|
6
15
|
def call(arg, world = {})
|
7
16
|
is_hash!(arg, world)
|
8
17
|
|
@@ -3,11 +3,16 @@ module Monolens
|
|
3
3
|
class Transform
|
4
4
|
include Lens
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
signature(Type::Object, Type::Object, {
|
7
|
+
defn: [Type::Map.of(Type::Name, Type::Lenses), true],
|
8
|
+
on_missing: [Type::Strategy.missing(%w{fail null skip}), false]
|
9
|
+
})
|
10
|
+
|
11
|
+
def initialize(options, registry)
|
12
|
+
super(options, registry)
|
8
13
|
ts = option(:defn, {})
|
9
14
|
ts.each_pair do |k,v|
|
10
|
-
ts[k] =
|
15
|
+
ts[k] = lens(v)
|
11
16
|
end
|
12
17
|
end
|
13
18
|
|