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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +51 -85
  3. data/lib/monolens/command.rb +111 -14
  4. data/lib/monolens/error.rb +2 -0
  5. data/lib/monolens/file.rb +6 -0
  6. data/lib/monolens/jsonpath.rb +76 -0
  7. data/lib/monolens/lens/options.rb +26 -12
  8. data/lib/monolens/lens/signature/missing.rb +11 -0
  9. data/lib/monolens/lens/signature.rb +60 -0
  10. data/lib/monolens/lens.rb +25 -4
  11. data/lib/monolens/macros.rb +28 -0
  12. data/lib/monolens/namespace.rb +11 -0
  13. data/lib/monolens/registry.rb +77 -0
  14. data/lib/monolens/{array → stdlib/array}/compact.rb +2 -0
  15. data/lib/monolens/{array → stdlib/array}/join.rb +4 -0
  16. data/lib/monolens/{array → stdlib/array}/map.rb +13 -19
  17. data/lib/monolens/{array.rb → stdlib/array.rb} +8 -6
  18. data/lib/monolens/{check → stdlib/check}/not_empty.rb +4 -0
  19. data/lib/monolens/{check.rb → stdlib/check.rb} +4 -2
  20. data/lib/monolens/{coerce → stdlib/coerce}/date.rb +5 -0
  21. data/lib/monolens/{coerce → stdlib/coerce}/date_time.rb +6 -1
  22. data/lib/monolens/{coerce → stdlib/coerce}/integer.rb +4 -0
  23. data/lib/monolens/{coerce → stdlib/coerce}/string.rb +2 -0
  24. data/lib/monolens/{coerce.rb → stdlib/coerce.rb} +10 -8
  25. data/lib/monolens/{core → stdlib/core}/chain.rb +5 -3
  26. data/lib/monolens/{core → stdlib/core}/dig.rb +5 -0
  27. data/lib/monolens/stdlib/core/literal.rb +68 -0
  28. data/lib/monolens/{core → stdlib/core}/mapping.rb +15 -5
  29. data/lib/monolens/{core.rb → stdlib/core.rb} +10 -8
  30. data/lib/monolens/stdlib/object/allbut.rb +22 -0
  31. data/lib/monolens/{object → stdlib/object}/extend.rb +10 -5
  32. data/lib/monolens/{object → stdlib/object}/keys.rb +4 -0
  33. data/lib/monolens/stdlib/object/merge.rb +56 -0
  34. data/lib/monolens/{object → stdlib/object}/rename.rb +5 -1
  35. data/lib/monolens/{object → stdlib/object}/select.rb +9 -0
  36. data/lib/monolens/{object → stdlib/object}/transform.rb +8 -3
  37. data/lib/monolens/{object → stdlib/object}/values.rb +9 -4
  38. data/lib/monolens/stdlib/object.rb +55 -0
  39. data/lib/monolens/{skip → stdlib/skip}/null.rb +2 -0
  40. data/lib/monolens/{skip.rb → stdlib/skip.rb} +4 -2
  41. data/lib/monolens/{str → stdlib/str}/downcase.rb +2 -0
  42. data/lib/monolens/{str → stdlib/str}/split.rb +5 -1
  43. data/lib/monolens/{str → stdlib/str}/strip.rb +2 -0
  44. data/lib/monolens/{str → stdlib/str}/upcase.rb +2 -0
  45. data/lib/monolens/{str.rb → stdlib/str.rb} +10 -8
  46. data/lib/monolens/stdlib.rb +7 -0
  47. data/lib/monolens/type/any.rb +39 -0
  48. data/lib/monolens/type/array.rb +27 -0
  49. data/lib/monolens/type/boolean.rb +17 -0
  50. data/lib/monolens/type/callback.rb +17 -0
  51. data/lib/monolens/type/coercible.rb +10 -0
  52. data/lib/monolens/type/diggable.rb +9 -0
  53. data/lib/monolens/type/emptyable.rb +9 -0
  54. data/lib/monolens/type/integer.rb +18 -0
  55. data/lib/monolens/type/lenses.rb +17 -0
  56. data/lib/monolens/type/map.rb +30 -0
  57. data/lib/monolens/type/object.rb +17 -0
  58. data/lib/monolens/type/responding.rb +25 -0
  59. data/lib/monolens/type/strategy.rb +56 -0
  60. data/lib/monolens/type/string.rb +18 -0
  61. data/lib/monolens/type/symbol.rb +20 -0
  62. data/lib/monolens/type.rb +33 -0
  63. data/lib/monolens/version.rb +2 -2
  64. data/lib/monolens.rb +22 -66
  65. data/spec/fixtures/macro.yml +13 -0
  66. data/spec/fixtures/recursive.yml +15 -0
  67. data/spec/monolens/command/literal.yml +2 -0
  68. data/spec/monolens/command/literal2.yml +2 -0
  69. data/spec/monolens/command/upcase.lens.yml +4 -0
  70. data/spec/monolens/lens/test_options.rb +2 -14
  71. data/spec/monolens/lens/test_signature.rb +38 -0
  72. data/spec/monolens/{array → stdlib/array}/test_compact.rb +8 -0
  73. data/spec/monolens/{array → stdlib/array}/test_join.rb +0 -0
  74. data/spec/monolens/{array → stdlib/array}/test_map.rb +15 -0
  75. data/spec/monolens/{check → stdlib/check}/test_not_empty.rb +0 -0
  76. data/spec/monolens/{coerce → stdlib/coerce}/test_date.rb +0 -0
  77. data/spec/monolens/{coerce → stdlib/coerce}/test_datetime.rb +1 -1
  78. data/spec/monolens/{coerce → stdlib/coerce}/test_integer.rb +0 -0
  79. data/spec/monolens/{coerce → stdlib/coerce}/test_string.rb +0 -0
  80. data/spec/monolens/{core → stdlib/core}/test_dig.rb +0 -0
  81. data/spec/monolens/stdlib/core/test_literal.rb +73 -0
  82. data/spec/monolens/{core → stdlib/core}/test_mapping.rb +37 -1
  83. data/spec/monolens/stdlib/object/test_allbut.rb +31 -0
  84. data/spec/monolens/{object → stdlib/object}/test_extend.rb +0 -0
  85. data/spec/monolens/{object → stdlib/object}/test_keys.rb +0 -0
  86. data/spec/monolens/stdlib/object/test_merge.rb +133 -0
  87. data/spec/monolens/{object → stdlib/object}/test_rename.rb +0 -0
  88. data/spec/monolens/{object → stdlib/object}/test_select.rb +0 -0
  89. data/spec/monolens/{object → stdlib/object}/test_transform.rb +0 -0
  90. data/spec/monolens/{object → stdlib/object}/test_values.rb +0 -0
  91. data/spec/monolens/{skip → stdlib/skip}/test_null.rb +0 -0
  92. data/spec/monolens/{str → stdlib/str}/test_downcase.rb +0 -0
  93. data/spec/monolens/{str → stdlib/str}/test_split.rb +0 -0
  94. data/spec/monolens/{str → stdlib/str}/test_strip.rb +0 -0
  95. data/spec/monolens/{str → stdlib/str}/test_upcase.rb +0 -0
  96. data/spec/monolens/test_command.rb +145 -0
  97. data/spec/monolens/test_error_traceability.rb +1 -1
  98. data/spec/monolens/test_jsonpath.rb +88 -0
  99. data/spec/monolens/test_lens.rb +1 -1
  100. data/spec/test_documentation.rb +52 -0
  101. data/spec/test_monolens.rb +20 -0
  102. data/tasks/test.rake +1 -1
  103. metadata +91 -55
  104. data/lib/monolens/core/literal.rb +0 -11
  105. data/lib/monolens/object.rb +0 -41
  106. data/spec/monolens/core/test_literal.rb +0 -13
@@ -3,6 +3,11 @@ module Monolens
3
3
  class Values
4
4
  include Lens
5
5
 
6
+ signature(Type::Object, Type::Object, {
7
+ lenses: [Type::Lenses, false],
8
+ on_error: [Type::Strategy.error(%w{fail handler keep null skip}), false],
9
+ })
10
+
6
11
  def call(arg, world = {})
7
12
  is_hash!(arg, world)
8
13
 
@@ -26,16 +31,16 @@ module Monolens
26
31
  case strategy
27
32
  when ::Array
28
33
  strategy.each{|s| handle_error(s, ex, result, attr, value, world) }
29
- when :handler
30
- error_handler!(world).call(ex)
31
34
  when :fail
32
35
  raise
36
+ when :handler
37
+ error_handler!(world).call(ex)
38
+ when :keep
39
+ result[attr] = value
33
40
  when :null
34
41
  result[attr] = nil
35
42
  when :skip
36
43
  result.delete(attr)
37
- when :keep
38
- result[attr] = value
39
44
  else
40
45
  raise Monolens::Error, "Unexpected error strategy `#{strategy}`"
41
46
  end
@@ -0,0 +1,55 @@
1
+ module Monolens
2
+ module Object
3
+ extend Namespace
4
+
5
+ def allbut(options, registry)
6
+ Allbut.new(options, registry)
7
+ end
8
+ module_function :allbut
9
+
10
+ def extend(options, registry)
11
+ Extend.new(options, registry)
12
+ end
13
+ module_function :extend
14
+
15
+ def rename(options, registry)
16
+ Rename.new(options, registry)
17
+ end
18
+ module_function :rename
19
+
20
+ def transform(options, registry)
21
+ Transform.new(options, registry)
22
+ end
23
+ module_function :transform
24
+
25
+ def keys(options, registry)
26
+ Keys.new(options, registry)
27
+ end
28
+ module_function :keys
29
+
30
+ def values(options, registry)
31
+ Values.new(options, registry)
32
+ end
33
+ module_function :values
34
+
35
+ def select(options, registry)
36
+ Select.new(options, registry)
37
+ end
38
+ module_function :select
39
+
40
+ def merge(options, registry)
41
+ Merge.new(options, registry)
42
+ end
43
+ module_function :merge
44
+
45
+ Monolens.define_namespace 'object', self
46
+ end
47
+ end
48
+ require_relative 'object/allbut'
49
+ require_relative 'object/rename'
50
+ require_relative 'object/transform'
51
+ require_relative 'object/keys'
52
+ require_relative 'object/values'
53
+ require_relative 'object/select'
54
+ require_relative 'object/extend'
55
+ require_relative 'object/merge'
@@ -3,6 +3,8 @@ module Monolens
3
3
  class Null
4
4
  include Lens
5
5
 
6
+ signature(Type::Any, Type::Any)
7
+
6
8
  def call(arg, world = {})
7
9
  throw :skip if arg.nil?
8
10
 
@@ -1,7 +1,9 @@
1
1
  module Monolens
2
2
  module Skip
3
- def null(options = {})
4
- Null.new(options)
3
+ extend Namespace
4
+
5
+ def null(options, registry)
6
+ Null.new(options, registry)
5
7
  end
6
8
  module_function :null
7
9
 
@@ -3,6 +3,8 @@ module Monolens
3
3
  class Downcase
4
4
  include Lens
5
5
 
6
+ signature(Type::String, Type::String)
7
+
6
8
  def call(arg, world = {})
7
9
  is_string!(arg, world)
8
10
 
@@ -3,10 +3,14 @@ module Monolens
3
3
  class Split
4
4
  include Lens
5
5
 
6
+ signature(Type::String, Type::Array.of(Type::String), {
7
+ separator: [Type::String, false]
8
+ })
9
+
6
10
  def call(arg, world = {})
7
11
  is_string!(arg, world)
8
12
 
9
- sep = option(:separator)
13
+ sep = option(:separator, ' ')
10
14
  sep ? arg.split(sep) : arg.split
11
15
  end
12
16
  end
@@ -3,6 +3,8 @@ module Monolens
3
3
  class Strip
4
4
  include Lens
5
5
 
6
+ signature(Type::String, Type::String)
7
+
6
8
  def call(arg, world = {})
7
9
  is_string!(arg, world)
8
10
 
@@ -3,6 +3,8 @@ module Monolens
3
3
  class Upcase
4
4
  include Lens
5
5
 
6
+ signature(Type::String, Type::String)
7
+
6
8
  def call(arg, world = {})
7
9
  is_string!(arg, world)
8
10
 
@@ -1,22 +1,24 @@
1
1
  module Monolens
2
2
  module Str
3
- def downcase(options = {})
4
- Downcase.new(options)
3
+ extend Namespace
4
+
5
+ def downcase(options, registry)
6
+ Downcase.new(options, registry)
5
7
  end
6
8
  module_function :downcase
7
9
 
8
- def strip(options = {})
9
- Strip.new(options)
10
+ def strip(options, registry)
11
+ Strip.new(options, registry)
10
12
  end
11
13
  module_function :strip
12
14
 
13
- def split(options = {})
14
- Split.new(options)
15
+ def split(options, registry)
16
+ Split.new(options, registry)
15
17
  end
16
18
  module_function :split
17
19
 
18
- def upcase(options = {})
19
- Upcase.new(options)
20
+ def upcase(options, registry)
21
+ Upcase.new(options, registry)
20
22
  end
21
23
  module_function :upcase
22
24
 
@@ -0,0 +1,7 @@
1
+ require_relative 'stdlib/core'
2
+ require_relative 'stdlib/skip'
3
+ require_relative 'stdlib/str'
4
+ require_relative 'stdlib/array'
5
+ require_relative 'stdlib/object'
6
+ require_relative 'stdlib/coerce'
7
+ require_relative 'stdlib/check'
@@ -0,0 +1,39 @@
1
+ module Monolens
2
+ module Type
3
+ class Any
4
+ include Type::ErrorHandling
5
+
6
+ def initialize(candidates)
7
+ @candidates = candidates
8
+ end
9
+
10
+ def self.of(*candidates)
11
+ Any.new(candidates)
12
+ end
13
+
14
+ def self.dress(instance, registry)
15
+ instance
16
+ end
17
+
18
+ def self.===(instance)
19
+ true
20
+ end
21
+
22
+ def ===(instance)
23
+ @candidates.any?{|c| c === instance }
24
+ end
25
+
26
+ def dress(instance, registry, &block)
27
+ first_error = nil
28
+ @candidates.each do |candidate|
29
+ begin
30
+ return candidate.dress(instance, registry, &block)
31
+ rescue TypeError => ex
32
+ first_error ||= ex
33
+ end
34
+ end
35
+ fail!(first_error.message, &block)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ module Monolens
2
+ module Type
3
+ class Array
4
+ include Type::ErrorHandling
5
+
6
+ def initialize(item_type)
7
+ @item_type = item_type
8
+ end
9
+
10
+ def self.of(item_type)
11
+ Array.new(item_type)
12
+ end
13
+
14
+ def dress(instance, registry, &block)
15
+ fail!("Array expected, got #{instance.class}", &block) unless instance.is_a?(::Array)
16
+
17
+ instance.map{|item| @item_type.dress(item, registry, &block) }
18
+ end
19
+
20
+ def ===(instance)
21
+ instance.is_a?(::Enumerable) && instance.all?{|item|
22
+ @item_type === item
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ module Monolens
2
+ module Type
3
+ class Boolean
4
+ include Type::ErrorHandling
5
+
6
+ def self.dress(instance, registry, &block)
7
+ fail!("Invalid Boolean `#{instance}`") unless self === instance
8
+
9
+ instance
10
+ end
11
+
12
+ def self.===(instance)
13
+ instance == true || instance == false
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Monolens
2
+ module Type
3
+ class Callback
4
+ extend Type::ErrorHandling
5
+
6
+ def self.dress(instance, registry, &block)
7
+ fail!("Invalid #{instance}", &block) unless self === instance
8
+
9
+ instance
10
+ end
11
+
12
+ def self.===(instance)
13
+ instance.respond_to?(:call)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ module Monolens
2
+ module Type
3
+ class Coercible
4
+ def self.to(type)
5
+ # TODO: make me stricter
6
+ ::Object
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Monolens
2
+ module Type
3
+ class Diggable
4
+ def self.===(instance)
5
+ instance.respond_to?(:dig)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Monolens
2
+ module Type
3
+ class Emptyable
4
+ def self.===(instance)
5
+ instance.respond_to?(:empty)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+
2
+ module Monolens
3
+ module Type
4
+ class Integer
5
+ extend Type::ErrorHandling
6
+
7
+ def self.===(instance)
8
+ instance.is_a?(::Integer)
9
+ end
10
+
11
+ def self.dress(instance, registry, &block)
12
+ fail!("Invalid integer #{instance}", &block) unless self === instance
13
+
14
+ instance
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ module Monolens
2
+ module Type
3
+ class Lenses
4
+ extend Type::ErrorHandling
5
+
6
+ def self.===(arg)
7
+ arg.is_a?(Lens)
8
+ end
9
+
10
+ def self.dress(value, registry, &block)
11
+ registry.lens(value)
12
+ rescue TypeError => ex
13
+ fail!(ex.message, &block)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ module Monolens
2
+ module Type
3
+ class Map
4
+ include Type::ErrorHandling
5
+
6
+ def initialize(key_type, value_type)
7
+ @key_type = key_type
8
+ @value_type = value_type
9
+ end
10
+
11
+ def self.of(key_type, value_type)
12
+ Map.new(key_type, value_type)
13
+ end
14
+
15
+ def dress(value, registry, &block)
16
+ fail!("Map expected, got #{value.class}", &block) unless value.is_a?(::Hash)
17
+
18
+ value.each_with_object({}) do |(k,v), memo|
19
+ memo[@key_type.dress(k, registry, &block)] = @value_type.dress(v, registry, &block)
20
+ end
21
+ end
22
+
23
+ def ===(instance)
24
+ instance.is_a?(::Hash) && instance.all?{|(k,v)|
25
+ @key_type === k && @value_type === v
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ module Monolens
2
+ module Type
3
+ class Object
4
+ extend Type::ErrorHandling
5
+
6
+ def self.dress(instance, registry, &block)
7
+ fail!("Object expected, got #{instance.class}", &block) unless instance.is_a?(::Hash)
8
+
9
+ instance
10
+ end
11
+
12
+ def self.===(instance)
13
+ instance.is_a?(::Hash)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ module Monolens
2
+ module Type
3
+ class Responding
4
+ include Type::ErrorHandling
5
+
6
+ def initialize(messages)
7
+ @messages = messages
8
+ end
9
+
10
+ def self.to(*messages)
11
+ new(messages)
12
+ end
13
+
14
+ def dress(instance, registry, &block)
15
+ fail!("Invalid #{instance}", &block) unless self === instance
16
+
17
+ instance
18
+ end
19
+
20
+ def ===(instance)
21
+ @messages.all?{|m| instance.respond_to?(m) }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,56 @@
1
+ module Monolens
2
+ module Type
3
+ class Strategy
4
+ include Type::ErrorHandling
5
+
6
+ def initialize(kind, valid)
7
+ @kind = kind
8
+ @valid = valid
9
+ end
10
+
11
+ def self.selection(valid)
12
+ new('selection', valid)
13
+ end
14
+
15
+ def self.error(valid)
16
+ new('error', valid)
17
+ end
18
+
19
+ def self.missing(valid)
20
+ new('missing', valid)
21
+ end
22
+
23
+ def self.priority(valid)
24
+ new('priority', valid)
25
+ end
26
+
27
+ def dress(arg, registry, &block)
28
+ case arg
29
+ when ::Symbol
30
+ fail!(arg, &block) unless @valid.include?(arg.to_s)
31
+ arg
32
+ when ::String
33
+ fail!(arg, &block) unless @valid.include?(arg)
34
+ arg.to_sym
35
+ when ::Array
36
+ fail!(arg, &block) unless (arg.map(&:to_s) - @valid).empty?
37
+ arg.map(&:to_sym)
38
+ else
39
+ fail!(arg, &block)
40
+ end
41
+ end
42
+
43
+ def ===(arg)
44
+ !!dress(arg, nil)
45
+ rescue TypeError
46
+ false
47
+ end
48
+
49
+ private
50
+
51
+ def fail!(arg, &block)
52
+ super("Invalid #{kind}strategy `#{arg}`", &block)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,18 @@
1
+
2
+ module Monolens
3
+ module Type
4
+ class String
5
+ extend Type::ErrorHandling
6
+
7
+ def self.===(instance)
8
+ instance.is_a?(::String)
9
+ end
10
+
11
+ def self.dress(instance, registry, &block)
12
+ fail!("Invalid string #{instance}", &block) unless self === instance
13
+
14
+ instance
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+
2
+ module Monolens
3
+ module Type
4
+ class Symbol
5
+ extend Type::ErrorHandling
6
+
7
+ def self.===(instance)
8
+ instance.is_a?(::Symbol)
9
+ end
10
+
11
+ def self.dress(instance, registry, &block)
12
+ unless instance.is_a?(::String) or instance.is_a?(::Symbol)
13
+ fail!("Invalid symbol #{instance}", &block)
14
+ end
15
+
16
+ instance.to_sym
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ module Monolens
2
+ module Type
3
+ module ErrorHandling
4
+ def fail!(message, &block)
5
+ block.call(message)
6
+ end
7
+ end
8
+
9
+ require_relative 'type/any'
10
+ require_relative 'type/array'
11
+ require_relative 'type/boolean'
12
+ require_relative 'type/callback'
13
+ require_relative 'type/coercible'
14
+ require_relative 'type/emptyable'
15
+ require_relative 'type/diggable'
16
+ require_relative 'type/integer'
17
+ require_relative 'type/map'
18
+ require_relative 'type/responding'
19
+ require_relative 'type/lenses'
20
+ require_relative 'type/object'
21
+ require_relative 'type/strategy'
22
+ require_relative 'type/string'
23
+ require_relative 'type/symbol'
24
+
25
+ Date = ::Date
26
+
27
+ DateTime = ::DateTime
28
+
29
+ DateTimeParser = Responding.to(:parse, :strptime)
30
+
31
+ Name = Any.of(Type::Symbol, Type::String)
32
+ end
33
+ end
@@ -1,8 +1,8 @@
1
1
  module Monolens
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 5
5
- TINY = 3
4
+ MINOR = 6
5
+ TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end