monolens 0.5.2 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +51 -84
  3. data/lib/monolens/command/tester.rb +95 -0
  4. data/lib/monolens/command.rb +137 -18
  5. data/lib/monolens/error.rb +2 -0
  6. data/lib/monolens/file.rb +11 -0
  7. data/lib/monolens/jsonpath.rb +76 -0
  8. data/lib/monolens/lens/options.rb +26 -12
  9. data/lib/monolens/lens/signature/missing.rb +11 -0
  10. data/lib/monolens/lens/signature.rb +60 -0
  11. data/lib/monolens/lens.rb +25 -4
  12. data/lib/monolens/macros.rb +28 -0
  13. data/lib/monolens/namespace.rb +11 -0
  14. data/lib/monolens/registry.rb +77 -0
  15. data/lib/monolens/{array → stdlib/array}/compact.rb +2 -0
  16. data/lib/monolens/{array → stdlib/array}/join.rb +4 -0
  17. data/lib/monolens/{array → stdlib/array}/map.rb +13 -19
  18. data/lib/monolens/{array.rb → stdlib/array.rb} +8 -6
  19. data/lib/monolens/{check → stdlib/check}/not_empty.rb +4 -0
  20. data/lib/monolens/{check.rb → stdlib/check.rb} +4 -2
  21. data/lib/monolens/{coerce → stdlib/coerce}/date.rb +5 -0
  22. data/lib/monolens/{coerce → stdlib/coerce}/date_time.rb +6 -1
  23. data/lib/monolens/{coerce → stdlib/coerce}/integer.rb +4 -0
  24. data/lib/monolens/{coerce → stdlib/coerce}/string.rb +2 -0
  25. data/lib/monolens/{coerce.rb → stdlib/coerce.rb} +10 -8
  26. data/lib/monolens/{core → stdlib/core}/chain.rb +5 -3
  27. data/lib/monolens/{core → stdlib/core}/dig.rb +5 -0
  28. data/lib/monolens/stdlib/core/literal.rb +68 -0
  29. data/lib/monolens/{core → stdlib/core}/mapping.rb +15 -5
  30. data/lib/monolens/stdlib/core.rb +31 -0
  31. data/lib/monolens/stdlib/object/allbut.rb +22 -0
  32. data/lib/monolens/{object → stdlib/object}/extend.rb +10 -5
  33. data/lib/monolens/{object → stdlib/object}/keys.rb +4 -0
  34. data/lib/monolens/stdlib/object/merge.rb +56 -0
  35. data/lib/monolens/{object → stdlib/object}/rename.rb +5 -1
  36. data/lib/monolens/{object → stdlib/object}/select.rb +9 -0
  37. data/lib/monolens/{object → stdlib/object}/transform.rb +8 -3
  38. data/lib/monolens/{object → stdlib/object}/values.rb +9 -4
  39. data/lib/monolens/stdlib/object.rb +55 -0
  40. data/lib/monolens/{skip → stdlib/skip}/null.rb +2 -0
  41. data/lib/monolens/{skip.rb → stdlib/skip.rb} +4 -2
  42. data/lib/monolens/{str → stdlib/str}/downcase.rb +2 -0
  43. data/lib/monolens/{str → stdlib/str}/split.rb +5 -1
  44. data/lib/monolens/{str → stdlib/str}/strip.rb +2 -0
  45. data/lib/monolens/{str → stdlib/str}/upcase.rb +2 -0
  46. data/lib/monolens/{str.rb → stdlib/str.rb} +10 -8
  47. data/lib/monolens/stdlib.rb +7 -0
  48. data/lib/monolens/type/any.rb +39 -0
  49. data/lib/monolens/type/array.rb +27 -0
  50. data/lib/monolens/type/boolean.rb +17 -0
  51. data/lib/monolens/type/callback.rb +17 -0
  52. data/lib/monolens/type/coercible.rb +10 -0
  53. data/lib/monolens/type/diggable.rb +9 -0
  54. data/lib/monolens/type/emptyable.rb +9 -0
  55. data/lib/monolens/type/integer.rb +18 -0
  56. data/lib/monolens/type/lenses.rb +17 -0
  57. data/lib/monolens/type/map.rb +30 -0
  58. data/lib/monolens/type/object.rb +17 -0
  59. data/lib/monolens/type/responding.rb +25 -0
  60. data/lib/monolens/type/strategy.rb +56 -0
  61. data/lib/monolens/type/string.rb +18 -0
  62. data/lib/monolens/type/symbol.rb +20 -0
  63. data/lib/monolens/type.rb +33 -0
  64. data/lib/monolens/version.rb +2 -2
  65. data/lib/monolens.rb +22 -66
  66. data/spec/fixtures/macro.yml +13 -0
  67. data/spec/fixtures/recursive.yml +15 -0
  68. data/spec/monolens/command/literal.yml +2 -0
  69. data/spec/monolens/command/literal2.yml +2 -0
  70. data/spec/monolens/command/test-ko-complex.yml +15 -0
  71. data/spec/monolens/command/test-ko.lens.yml +13 -0
  72. data/spec/monolens/command/test-ok.lens.yml +9 -0
  73. data/spec/monolens/command/upcase.lens.yml +4 -0
  74. data/spec/monolens/lens/test_options.rb +2 -14
  75. data/spec/monolens/lens/test_signature.rb +38 -0
  76. data/spec/monolens/{array → stdlib/array}/test_compact.rb +8 -0
  77. data/spec/monolens/{array → stdlib/array}/test_join.rb +0 -0
  78. data/spec/monolens/{array → stdlib/array}/test_map.rb +15 -0
  79. data/spec/monolens/{check → stdlib/check}/test_not_empty.rb +0 -0
  80. data/spec/monolens/{coerce → stdlib/coerce}/test_date.rb +0 -0
  81. data/spec/monolens/{coerce → stdlib/coerce}/test_datetime.rb +1 -1
  82. data/spec/monolens/{coerce → stdlib/coerce}/test_integer.rb +0 -0
  83. data/spec/monolens/{coerce → stdlib/coerce}/test_string.rb +0 -0
  84. data/spec/monolens/{core → stdlib/core}/test_dig.rb +0 -0
  85. data/spec/monolens/stdlib/core/test_literal.rb +73 -0
  86. data/spec/monolens/{core → stdlib/core}/test_mapping.rb +37 -1
  87. data/spec/monolens/stdlib/object/test_allbut.rb +31 -0
  88. data/spec/monolens/{object → stdlib/object}/test_extend.rb +0 -0
  89. data/spec/monolens/{object → stdlib/object}/test_keys.rb +0 -0
  90. data/spec/monolens/stdlib/object/test_merge.rb +133 -0
  91. data/spec/monolens/{object → stdlib/object}/test_rename.rb +0 -0
  92. data/spec/monolens/{object → stdlib/object}/test_select.rb +0 -0
  93. data/spec/monolens/{object → stdlib/object}/test_transform.rb +0 -0
  94. data/spec/monolens/{object → stdlib/object}/test_values.rb +0 -0
  95. data/spec/monolens/{skip → stdlib/skip}/test_null.rb +0 -0
  96. data/spec/monolens/{str → stdlib/str}/test_downcase.rb +0 -0
  97. data/spec/monolens/{str → stdlib/str}/test_split.rb +0 -0
  98. data/spec/monolens/{str → stdlib/str}/test_strip.rb +0 -0
  99. data/spec/monolens/{str → stdlib/str}/test_upcase.rb +0 -0
  100. data/spec/monolens/test_command.rb +179 -1
  101. data/spec/monolens/test_error_traceability.rb +1 -1
  102. data/spec/monolens/test_jsonpath.rb +88 -0
  103. data/spec/monolens/test_lens.rb +1 -1
  104. data/spec/test_documentation.rb +52 -0
  105. data/spec/test_monolens.rb +20 -0
  106. data/tasks/test.rake +1 -1
  107. metadata +124 -55
  108. data/lib/monolens/core.rb +0 -23
  109. data/lib/monolens/object.rb +0 -41
@@ -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
- def initialize(options)
7
- super(options)
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] = Monolens.lens(v)
15
+ ts[k] = lens(v)
11
16
  end
12
17
  end
13
18
 
@@ -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