monolens 0.5.3 → 0.6.0

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